SpringSecurity+JWT+Autho2整合
一. SpringSecurity简介
- Spring家族一员。是一个能够为基于Spring的企业应用系统提供声明式的安全访
问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC , DI(控制反转Inversion of Control,DI:Dependency Injection 依赖注入)和 AOP(面向切面编程) 功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
二. SpringSecurity快速入门
①. 导入依赖
<!--spring security组件-->
<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>

②. 登录页面
<!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 已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。

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

⑤. UserDetails详解
- 返回值 UserDetails 是一个接口,定义如下


⑥. PasswordEncoder 密码解析器详解
- Spring Security 要求容器中必须有 PasswordEncoder 实例。所以当自定义登录逻辑时要求必须给容器注入 PaswordEncoder 的bean对象。

- encode() :把参数按照特定的解析规则进行解析。
- matches() :验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹配,则返回 true;如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个参数表示存储的密码。
- upgradeEncoding() :如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回 false。默认返回 false。
⑦. 自定义登录逻辑_修改配置类
1. 登录页面配置
- 修改配置类中主要是设置哪个页面是登录页面。配置类需要继承WebSecurityConfigurerAdapte,并重写 configure 方法。
- successForwardUrl() :登录成功后跳转地址
- loginPage() :登录页面
- loginProcessingUrl :登录页面表单提交地址,此地址可以不真实存在。
- antMatchers() :匹配内容
- permitAll() :允许
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//当发现/login时认为是登录,必须和表单提交的地址一样。去执行UserServiceImpl
.loginProcessingUrl("/login")
//登录成功后跳转页面,POST请求
.successForwardUrl("/toMain");
http.authorizeRequests()
//login.html不需要被认证
.antMatchers("/login.html").permitAll()
//所有请求都必须被认证,必须登录后被访问
.anyRequest().authenticated();
//关闭csrf防护
http.csrf().disable();
}
@Bean
public PasswordEncoder getPw(){
return new BCryptPasswordEncoder();
}
}
2. 失败跳转

3. 添加控制器的方法

4. 设置请求账户和密码的参数名


5. 自定义登录成功处理器


6. 自定义登录失败处理器


7. 访问控制url匹配
anyRequest()
- 一般情况下此方法都会使用,设置全部内容都需要进行认证。

antMatcher()
- 在实际项目中经常需要放行所有静态资源

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

mvcMatchers()
- mvcMatchers()适用于配置了 servletPath 的情况。

8. 内置访问控制方法
- Spring Security 匹配了 URL 后调用了 permitAll() 表示不需要认证,随意访问。在 Spring Security
中提供了多种内置控制。
permitAll()
- permitAll()表示所匹配的 URL 任何人都允许访问。

anonymous()
- anonymous()表示可以匿名访问匹配的URL。和permitAll()效果类似,只是设置为 anonymous()的 url会执行 filter 链中
rememberMe()
- 被“remember me”的用户允许访问
fullyAuthenticated()
- 如果用户不是被 remember me 的,才可以访问。
9. 角色权限判断
- 除了之前讲解的内置权限控制。Spring Security 中还支持很多其他权限控制。这些方法一般都用于用
户已经被认证后,判断用户是否具有特定的要求。
hasAuthority(String)
- 判断用户是否具有特定的权限,用户的权限是在自定义登录逻辑中创建 User 对象时指定的。下图中admin和normal 就是用户的权限。admin和normal 严格区分大小写。

hasAnyAuthority(String …)
- 如果用户具备给定权限中某一个,就允许访问。

hasRole(String)
- 如果用户具备给定角色就允许访问。否则出现 403。

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

hasIpAddress(String)
- 如果请求是指定的 IP 就运行访问。可以通过 request.getRemoteAddr() 获取 ip 地址。

10. 自定义403处理方案



11. 基于表达式的访问控制
access()方法使用

使用自定义方法
- 判断登录用户是否具有访问当前 URL 权限。



⑨. 基于注解的访问控制
开启注解

@Secured
- @Secured 是专门用于判断是否具有角色的。能写在方法或类上。参数要以 ROLE_开头。

@PreAuthorize/@PostAuthorize
- @PreAuthorize 表示访问方法或类在执行之前先判断权限,大多情况下都是使用这个注解,注解的参数和access()方法参数取值相同,都是权限表达式。
- @PostAuthorize 表示方法或类执行结束后判断权限,此注解很少被使用到。

⑩. RememberMe功能实现
- Spring Security 中 Remember Me 为“记住我”功能,用户只需要在登录时添加 remember-me复选
框,取值为true。Spring Security 会自动把用户信息存储到数据源中,以后就可以不登录进行访问
1. 添加依赖
- Spring Security 实 现 Remember Me 功 能 时 底 层 实 现 依 赖Spring-JDBC,所以需要导入 SpringJDBC。以后多使用 MyBatis 框架而很少直接导入 spring-jdbc,所以此处导入 mybatis 启动器同时还需
要添加 MySQL 驱动。

2. 配置数据源
- 在 application.properties 中配置数据源。
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url= jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username= root
spring.datasource.password= 1234
3. 编写配置



4. 在客户端页面添加复选框
- 在客户端登录页面中添加 remember-me 的复选框,只要用户勾选了复选框下次就不需要进行登录了。

5. 有效时间

十一. Thymeleaf中SpringSecurity的使用
1. 导入依赖

2. 在 html 页面中引入 thymeleaf 命名空间和 security 命名空间

3. 获取属性
- 可以在html页面中通过 sec:authentication=“” 获取
UsernamePasswordAuthenticationToken 中所有 getXXX 的内容,包含父类中的 getXXX 的内容。 - 根据源码得出下面属性:
- name :登录账号名称
- principal :登录主体,在自定义登录逻辑中是 UserDetails
- credentials :凭证
- authorities :权限和角色
- details :实际上是 WebAuthenticationDetails 的实例。可以获取 remoteAddress (客户端ip)和 sessionId (当前 sessionId)



十二. 退出登录
十三. SpringSecurity中的CSRF
- 在配置类中一直存在这样一行代码: http.csrf().disable(); 如果没有这行代码导致用户无法被认证。这行代码的含义是:关闭 csrf 防护。
1. 什么是CSRF
- CSRF(Cross-site request forgery)跨站请求伪造,也被称为“OneClick Attack” 或者 SessionRiding。通过伪造用户请求访问受信任站点的非法请求访问。
- 跨域:只要网络协议,ip 地址,端口中任何一个不相同就是跨域请求。
- 客户端与服务进行交互时,由于 http 协议本身是无状态协议,所以引入了cookie进行记录客户端身份。在cookie中会存放session id用来识别客户端身份的。在跨域的情况下,session id 可能被第三方恶意劫持,通过这个 session id 向服务端发起请求时,服务端会认为这个请求是合法的,可能发生很多意想不到的事情。
2. Spring Security中的CSRF
- 从 Spring Security4开始CSRF防护默认开启。默认会拦截请求。进行CSRF处理。CSRF为了保证不是其他第三方网站访问,要求访问时携带参数名为 _csrf 值为token(token 在服务端产生)的内容,如果token和服务端的token匹配成功,则正常访问。




6167

被折叠的 条评论
为什么被折叠?



