轻松上手springsecurity,oauth,jwt(代码片段)

Serendipitysn Serendipitysn     2022-12-06     535

关键词:

目录

学习目标

一.SpringSecurity

1.SpringSecurity简介及快速入门

<1>.SpringSecurity简介

Spring Security是一个高度自定义的安全框架。利用 Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。使用 Spring Secruity 的原因有很多,但大部分都是发现了javaEE的 Servlet 规范或 EJB 规范中的安全功能缺乏典型企业应用场景。同时认识到他们在 WAR 或 EAR 级别无法移植。因此如果你更换服务器环境,还有大量工作去重新配置你的应用程序。使用 Spring Security解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。正如你可能知道的两个应用程序的两个主要区域是“认证”和“授 权”(或者访问控制)。这两点也是 Spring Security 重要核心功能。“认证”,是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。“授权”指确定一个主体是否允许在你的应用程序执行一个动作的过程。通俗点讲就是系统判断用户是否有权限去做某些事情

<2>.SpringSecurity快速入门

导入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>org.example</groupId>
	<artifactId>springsecuritydemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springsecuritydemo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<!--SpringSecurity组件-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<!--web组件-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--test组件-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- mybatis 依赖 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>
		<!-- mysql 数据库依赖 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.18</version>
		</dependency>
		<!--thymeleaf springsecurity5 依赖-->
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity5</artifactId>
		</dependency>
		<!--thymeleaf依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

导入前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="username123" /><br/>
    密码:<input type="password" name="password123" /><br/>
    记住我:<input type="checkbox" name="remember-me" value="true" /><br />
    <input type="submit" value="登录" />
</form>
</body>
</html>

访问页面:
导入spring-boot-starter-security 启动器后,Spring Security 已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。

默认的username为user,密码打印在控制台上,在浏览器中输入账号和密码后会显示 login.html 页面内容。

2.SpringSecurity基本原理

<1>.UserDetailsService详解

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现UserDetailsService 接口即可。

public interface UserDetailsService 
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

返回值是一个UserDetails接口:

public interface UserDetails extends Serializable 
	// ~ Methods
	Collection<? extends GrantedAuthority> getAuthorities();//获取所有权限
	String getPassword();//获取密码
	String getUsername();//获取用户名
	boolean isAccountNonExpired();//判断账号是否过期
	boolean isAccountNonLocked();//判断账号是否被锁定
	boolean isCredentialsNonExpired();//判断凭证(密码)是否过期
	boolean isEnabled();//是否可用

这里我们一般返回UserDetails的实现类User

<2>.PasswordEncoder 密码解析器详解

Spring Security 要求容器中必须有 PasswordEncoder 实例。所以当自定义登录逻辑时要求必须给容器注入PaswordEncoder 的bean对象。
接口介绍:

public interface PasswordEncoder 
	String encode(CharSequence rawPassword);//把参数按照特定的解析规则进行解析。
	//:验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹配,则返回 true;
如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个参数表示存储的密码。
	boolean matches(CharSequence rawPassword, String encodedPassword);
	//如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回 false。默认返回 false
	default boolean upgradeEncoding(String encodedPassword) 
		return false;
	

BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,平时多使用这个解析器
代码示例:

	@Test
	public void contextLoads() 
		PasswordEncoder pe = new BCryptPasswordEncoder();
		String encode = pe.encode("123");
		System.out.println(encode);
		boolean matches = pe.matches("1234", encode);
		System.out.println("========================");
		System.out.println(matches);
	

3. SpringSecurity自定义登录逻辑及权限控制

<1>.自定义逻辑登录

当 进 行 自 定 义 登 录 逻 辑 时 需 要 用 到 之 前 讲 解 的 UserDetailsService 和 PasswordEncoder 。但是Spring Security 要求:当进行自定义登录逻辑时容器内必须有 PasswordEncoder 实例。所以不能直接 new 对象。
代码示例:
第一步:编写配置类,注入PasswordEncoder Bean:

@Bean
	public PasswordEncoder getPw()
		return new BCryptPasswordEncoder();
	

第二步:编写自定义登录逻辑(账号密码需要从数据库获取,这里使用模拟的方法)

@Service
public class UserDetailsServiceImpl implements UserDetailsService 

	@Autowired
	private PasswordEncoder pw;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

		System.out.println("执行了loadUserByUsername方法");

		//1.查询数据库判断用户名是否存在,如果不存在就会抛出UsernameNotFoundException异常
		if (!"admin".equals(username))
			throw new UsernameNotFoundException("用户名不存在!");
		
		//2.把查询出来的密码(注册时已经加密过)进行解析,或者直接把密码放入构造方法
		String password = pw.encode("123");
		//加入相应的权限
		return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc," +
				"/main.html,/insert,/delete"));
	

重启项目后,在浏览器中输入账号:admin,密码:123。后可以正确进入到 login.html 页面。

<2>.自定义登录页面

1.修改配置类
修改配置类中主要是设置哪个页面是登录页面。配置类需要继承WebSecurityConfigurerAdapte,并重写 configure方法。

successForwardUrl() //登录成功后跳转地址
loginPage() //登录页面
loginProcessingUrl //登录页面表单提交地址,此地址可以不真实存在。
antMatchers() //匹配内容
permitAll() //允许

<3>.自定义成功处理器

使用successForwardUrl()时表示成功后转发请求到地址。内部是通过 successHandler() 方法进行控制成功后交给哪个类进行处理

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler 

	private String url;

	public MyAuthenticationSuccessHandler(String url) 
		this.url = url;
	

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException 
		System.out.println(request.getRemoteAddr());
		User user = (User) authentication.getPrincipal();
		System.out.println(user.getUsername());
		//输出null(保密)
		System.out.println(user.getPassword());
		System.out.println(user.getAuthorities());
		response.sendRedirect(url);
	

<4>.自定义失败处理器

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler 

	private String url;

	public MyAuthenticationFailureHandler(String url) 
		this.url = url;
	

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException 
		response.sendRedirect(url);
	

<5>.自定义登录配置代码示例

@Override
	protected void configure(HttpSecurity http) throws Exception 
		//表单提交
		http.formLogin()
				.usernameParameter("username123")
				.passwordParameter("password123")
				//当发现/login时认为是登录,必须和表单提交的地址一样,去执行UserDetailsServiceImpl
				.loginProcessingUrl("/login")
				//自定义登录页面
				.loginPage("/showLogin")
				//登录成功后跳转页面,Post请求
				.successForwardUrl("/toMain")
				//登录成功后处理器,不能和successForwardUrl共存
				// .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
				//登录失败后跳转页面,Post请求
				.failureForwardUrl("/toError");
				//登录失败后处理器,不能和failureForwardUrl共存
				// .failureHandler(new MyAuthenticationFailureHandler("/error.html"));

4.访问控制及角色权限判断

<1>.访问控制URL匹配

在所有匹配规则中取所有规则的交集。配置顺序影响了之后授权效果,越是具体的应该放在前面,越是笼统的应该放到后面

(1).anyRequest()

在之前认证过程中我们就已经使用过 anyRequest(),表示匹配所有的请求。一般情况下此方法都会使用,设置全部内容都需要进行认证。

.anyRequest().authenticated();

(2).antMatcher()

public C antMatchers(String... antPatterns)

参数是不定向参数,每个参数是一个 ant 表达式,用于匹配 URL规则。
规则如下:
? : 匹配一个字符
*:匹配 0 个或多个字符
** :匹配 0 个或多个目录

(3).regexMatchers()

使用正则表达式进行匹配。和 antMatchers() 主要的区别就是参数, antMatchers() 参数是 ant 表达式,regexMatchers() 参数是正则表达式

<2>.内置访问控制方法

1.permitAll()
permitAll()表示所匹配的 URL 任何人都允许访问
2.authenticated()
authenticated()表示所匹配的 URL 都需要被认证才能访问。
3.anonymous()
anonymous()表示可以匿名访问匹配的URL。和permitAll()效果类似,只是设置为 anonymous()的 url 会执行 filter链中
4.denyAll()
denyAll()表示所匹配的5. URL 都不允许被访问。
rememberMe()
被“remember me”的用户允许访问
5.fullyAuthenticated()
如果用户不是被 remember me 的,才可以访问

<3>.角色权限判断

1.hasAuthority(String)
判断用户是否具有特定的权限,用户的权限是在自定义登录逻辑中创建 User 对象时指定的。 admin和normal 就是用户的权限。admin和normal 严格区分大小写

	return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc," +
				"/main.html,/insert,/delete"));

在配置类中通过 hasAuthority(“admin”)设置具有 admin 权限时才能访问。

.antMatchers("/main1.html").hasAuthority("admin")

2.hasAnyAuthority(String …)
如果用户具备给定权限中某一个,就允许访问。下面代码中由于大小写和用户的权限不相同,所以用户无权访问

.antMatchers("/main1.html").hasAnyAuthority("adMin","admiN")

3.hasRole(String)
如果用户具备给定角色就允许访问。否则出现 403。
参数取值来源于自定义登录逻辑 UserDetailsService 实现类中创建 User 对象时给 User 赋予的授权。
在给用户赋予角色时角色需要以: ROLE_开头 ,后面添加角色名称。例如:ROLE_abc 其中 abc 是角色名,ROLE_是固定的字符开头。
使用 hasRole()时参数也只写 abc 即可。否则启动报错。

return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc," +
				"/main.html,/insert,/delete"));
.antMatchers("/main1.html").hasRole("abc")

4.hasAnyRole(String …)
如果用户具备给定角色的任意一个,就允许被访问

5.hasIpAddress(String)
如果请求是指定的 IP 就运行访问。
可以通过 request.getRemoteAddr() 获取 ip 地址。
需要注意的是在本机进行测试时 localhost 和 127.0.0.1 输出的 ip地址是不一样的。
当浏览器中通过 localhost 进行访问时控制台打印的内容:0:0:0:0:0:0:0:1

角色权限判断代码示例:


		//授权认证
		http.authorizeRequests()
				//error.html不需要被认证
				// .antMatchers("/error.html").permitAll()
				.antMatchers("/error.html").access("permitAll()")
				//login.html不需要被认证
				// .antMatchers("/login.html").permitAll()
				.antMatchers("/showLogin").access("permitAll()")
				.antMatchers("/js/**","/css/**"查看详情  

springsecurity与oauth2介绍

个人OAuth2全部文章SpringSecurity与OAuth2(介绍):https://www.jianshu.com/p/68f22f9a00eeSpringSecurity与OAuth2(授权服务器):https://www.jianshu.com/p/227f7e7503cbSpringSecurity与OAuth2(资源服务器):https://www.jianshu.com/p/6d 查看详情

springsecurity实现oauth2.0授权服务-进阶版

 《SpringSecurity实现OAuth2.0授权服务-基础版》介绍了如何使用SpringSecurity实现OAuth2.0授权和资源保护,但是使用的都是SpringSecurity默认的登录页、授权页,client和token信息也是保存在内存中的。 本文将介绍如何在SpringSecurityOAu... 查看详情

视频@轻松入门springsecurity

查看详情

使用springsecurity体验oauth2(入门2)

  本文继续使用SpringSecurity从实战角度对OAuth2进行体验,上一篇 搭建了项目环境,并对配置做了初步分析,分析发现会有两套配置可能在影响OAuth,一个是由授权服务的启动类上的注解@EnableAuthorizationServer引出的,另一个则... 查看详情

使用oauth2和匿名访问的springsecurity

我使用SpringSecurity和OAuth2保护了SpringRESTAPI,我可以成功检索令牌并访问我的API。我的应用程序自己定义OAuth2客户端。现在我希望用户对某些资源进行匿名访问。用例非常简单:我希望我的应用程序无需登录即可使用-但如果他们... 查看详情

springsecurity实战干货:简单的认识oauth2.0协议

1.前言欢迎阅读SpringSecurity实战干货系列文章。OAuth2.0是近几年比较流行的授权机制,对于普通用户来说可能每天你都在用它,我们经常使用的第三方登录大都基于OAuth2.0。随着应用的互联互通,个性化服务之间的相互调用,开放... 查看详情

springsecurity+oauth2.0登录认证+自定义验证

参考技术A1.导入依赖2.配置文件2.1SpringSecurityConfig2.2AuthorizationServer 查看详情

springsecurity---oauth2详解(代码片段)

SpringSecurity---Oauth2详解OAuth2需求场景OAuth2授权的流程OAuth2四种授权模式回顾OAuth2.0OAuth2.0与Spring社区现状SpringSecurity5.2不支持认证服务器实现授权码模式认证服务器maven坐标加载资源拥有者数据----用户认证服务器(授权码模式)获取... 查看详情

SpringSecurity WithSecurityContext MockMvc OAuth2 总是未经授权

】SpringSecurityWithSecurityContextMockMvcOAuth2总是未经授权【英文标题】:SpringSecurityWithSecurityContextMockMvcOAuth2alwaysunauthorised【发布时间】:2016-10-0102:22:29【问题描述】:例如,我已按照以下链接尝试测试OAuth2@PreAuthorise(hasAnyRole(\'ADMIN\',\'... 查看详情

springsecurity结合oauth2实现第三方授权

参考技术A流程【A服务客户端】需要用到【B服务资源服务】中的资源使用场景授权码模式是OAuth2中最安全最完善的一种模式,应用场景最广泛,可以实现服务之间的调用,常见的微信,QQ等第三方登录也可采用这种方式实现。说... 查看详情

源码时代java干货分享|springsecurity快速上手秘籍(代码片段)

...#xff0c;今天咱们探讨的是Spring旗下的一个款认证工具:SpringSecurity,如今认证框架主流“shiro”和“SpringSecurity”,由于和Spring的无缝衔接, 查看详情

springsecurity的oauth2的授权服务器配置(代码片段)

OAUTH2概念里有资源服务器与授权服务器先看授权服务的配置通常,我们会写一个AuthorizationServerConfiguration类继承自AuthorizationServerConfigurerAdapter,并且在类上加@Configuration注解授权服务器的配置@Configuration@EnableAuthorizationServerpu... 查看详情

使用jhipster,springsecurity和oauth2控制身份验证重定向

我希望能够在用户未登录时控制自动重定向到oauth2授权服务器。我生成了一个JHipsterGateway项目,下面的代码只是它的副本,添加了oAuth2ClientContextFilter变量,即autowired,然后我用它来setRedirectStrategy然而,当使用它时,变量是NULL。... 查看详情

Oauth 2.0 配置与 Spring Security 冲突

】Oauth2.0配置与SpringSecurity冲突【英文标题】:Oauth2.0configurationconflictswithSpringSecurity【发布时间】:2017-03-3122:10:27【问题描述】:我正在尝试使用SpringSecurity配置Oauth2。但是我的Oauth配置与SpringSecurity配置冲突。资源服务器配置似... 查看详情

springsecurity——oauth2框架鉴权实现源码分析(代码片段)

SpringSecurity——OAuth2框架鉴权实现源码分析一、ManagedFilter迭代过滤器链1.4springSecurityFilterChain1.4.7OAuth2AuthenticationProcessingFilter一、ManagedFilter迭代过滤器链ManagedFilter管理这六条过滤器链,如图所示:其中的第五条过滤器链spr... 查看详情

使用springsecurity登录认证,通过oauth2.0开发第三方授授权访问资源项目详解(代码片段)

1.OAuth2.0简介OAuth2.0提供者机制负责公开OAuth2.0受保护的资源。该配置包括建立可独立或代表用户访问其受保护资源的OAuth2.0客户端。提供者通过管理和验证用于访问受保护资源的OAuth2.0令牌来实现。在适用的情况下,提供商还必须... 查看详情

springsecurity实战内容:oauth2授权回调的处理机制(代码片段)

...de/*,所以我们只要找到拦截回调的过滤器就可以知道SpringSecurity是如何处理回调了。通过搜索确认了OAuth2LoginAuthenticationFilter就是处理回调的过滤器。OAuth2LoginAuthenticationFilter第三方认证服务器在调用redirect_uri时附加code和state... 查看详情