Spring Security
2021-12-17 19:17:00 77 举报
AI智能生成
Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架。它是保护基于Spring的应用程序的实际标准。Spring Security是一个能够为基于JavaEE的企业级应用程序提供身份认证和授权服务的框架。与所有Spring项目一样,Spring Security的真正强大之处在于它的自动化配置和扩展性。借助于自动配置,我们可以快速构建安全应用程序,而无需手动配置每个详细设置。同时,它还提供了许多可插拔的安全功能,例如OAuth2、JWT等,可以灵活地满足各种安全需求。总之,Spring Security是一个值得学习和使用的强大的安全框架。
作者其他创作
大纲/内容
Oauth2认证
Spring Security Oauth2
Spring Security Oauth2 整合单点登录(SSO)
SpringSecurity
SpringSecurity简介
快速入门
导入依赖
自己写的登陆页面login.html
启动项目
默认拦截全部请求,如果用户没有登录,
跳转到Security内置登录页面,内置登陆成功后才会跳到我们自己的登陆页面
跳转到Security内置登录页面,内置登陆成功后才会跳到我们自己的登陆页面
默认的 username 为 user,
password 打印在控制台中(每次重新启动都会刷新)
password 打印在控制台中(每次重新启动都会刷新)
实现自定义登录
UserDetailsService详解
需要自定义逻辑时,只需要实现 UserDetailsService 接口即可
重写loadUserByUsername方法,返回值是一个UserDetails
UserDetails是一个接口,我们只需返回它的一个实现类User
注意 User 的全限定路径是:
`org.springframework.security.core.userdetails.User`
此处经常和系统中自己开发的 User 类弄混
我们也可以自己编写一个User类实现UserDetails,进行我们需要的操作
UserDetails是一个接口,我们只需返回它的一个实现类User
注意 User 的全限定路径是:
`org.springframework.security.core.userdetails.User`
此处经常和系统中自己开发的 User 类弄混
我们也可以自己编写一个User类实现UserDetails,进行我们需要的操作
UserDetails接口
构造方法
方法参数
若要修改参数名需要在配置类配置
异常
设置权限
通过AuthorityUtils.commaSeparatedStringToAuthorityList(“”)
来创建authorities集合对象的。参数是一个字符串,多个权限使用逗号分隔。
来创建authorities集合对象的。参数是一个字符串,多个权限使用逗号分隔。
PasswordEncoder 密码解析器详解
Spring Security 要求容器中必须有`PasswordEncoder`实例
所以不能直接new对象,所以当自定义登录逻辑时
要求必须给容器注入`PaswordEncoder`的bean对象
在SecurityConfig中@Bean添加到容器
UserDetailsServiceImpl用的上,要注入
所以不能直接new对象,所以当自定义登录逻辑时
要求必须给容器注入`PaswordEncoder`的bean对象
在SecurityConfig中@Bean添加到容器
UserDetailsServiceImpl用的上,要注入
接口方法
内置解析器(即实现类)
自定义登陆逻辑
编写配置类SecurityConfig
配置类需要继承WebSecurityConfigurerAdapter,
并重写 configure 方法
@EnableWebSecurity是默认开启的
配置类需要继承WebSecurityConfigurerAdapter,
并重写 configure 方法
@EnableWebSecurity是默认开启的
在 Spring Security 中实现 UserDetailService 就表示为用户详情服务
配置类表单登陆相关方法
http.formLogin()
http.formLogin()
loginPage()
loginProcessingUrl()
usernamePasrameter(String)
passwordParameter(String)
默认情况只允许post请求登陆
=============
successForwardUrl()
failureForwardUrl()
自定义登录页面
访问控制(授权)
访问控制url匹配
在所有匹配规则中取所有规则的交集。
配置顺序影响了之后授权效果,
越是具体的应该放在前面,越是笼统的应该放到后面。
配置顺序影响了之后授权效果,
越是具体的应该放在前面,越是笼统的应该放到后面。
anyRequest()
匹配所有的请求
所有请求都必须认证才能访问,必须登陆 必须放在最后
.anyRequest().authenticated();
.anyRequest().authenticated();
自定义url访问.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)")
antMatcher()
单参数:参数是不定向参数,每个参数是一个 ant 表达式,用于匹配 URL规则
regexMatchers()
单参数:使用正则表达式进行匹配。和 antMatchers()主要的区别就是参数
mvcMatchers()(用的不多)
适用于配置了 servletPath(指的是图片第一种) 的情况
注意!!!context-path和path的区别
server.servlet.context-path:上下文路径
spring.mvc.servlet.path:DispatcherServlet 的拦截路径
意思是哪些访问路径需要被spring的dispatcher servlet处理
spring.mvc.servlet.path:DispatcherServlet 的拦截路径
意思是哪些访问路径需要被spring的dispatcher servlet处理
.mvcMatchers("/demo").servletPath("/novo").permitAll()
内置访问控制方法
接在URL匹配规则之后
permitAll()
authenticated()
包括rememberMe通过免登陆进来和fullyAuthenticated通过用户名和密码进来两种情况
anonymous()
和permitAll区别不大,用到比较少
denyAll()
rememberMe()
fullyAuthenticated()
角色、权限判断
用户的权限
hasAuthority(String)
hasAuthority(String)
hasAnyAuthority(String ...)
用户的角色
hasRole(String)
hasRole(String)
hasAnyRole(String ...)
hasIpAddress(String)用的不多
底层实现
都是调用access(表达式)
权限表达式的使用 官方文档
基于表达式的访问控制
举例:
.antMatchers("/login.html").access("permitAll")
等价于
.antMatchers("/login.html").permitAll()
.antMatchers("/login.html").access("permitAll")
等价于
.antMatchers("/login.html").permitAll()
.antMatchers("/main1.html").access("hasAnyRole('novo1','add')")
等价于 (注意双引号换成单引号)
.antMatchers("/main1.html").hasAnyRole("novo1","add")
等等...
等价于 (注意双引号换成单引号)
.antMatchers("/main1.html").hasAnyRole("novo1","add")
等等...
自定义逻辑
例:判断已登录用户是否具有访问当前 URL 权限
登陆成功后跳转到main.html
我们去设置main.html这个url是否有权限被访问
登陆成功后跳转到main.html
我们去设置main.html这个url是否有权限被访问
1、新建接口及实现类
MyService.java
MyServiceImpl.java
2、修改配置类SecurityConfig
在 access 中通过@bean的id名.方法(参数)的形式进行调用
即唯一标识id名首字母要小写
即唯一标识id名首字母要小写
基于注解的访问控制
注解默认值为false,不可用
要在引导类上加@EnableGlobalMethodSecurity开启具体的注解
要在引导类上加@EnableGlobalMethodSecurity开启具体的注解
比较常用:@PreAuthorize
如果设置的条件允许,程序正常执行。如果不允许会报 500
其实是先判断有没有登陆,如果登陆成功后还是没有权限才会报500,在此前我们没有权限是403
这些注解可以写到 Service 接口或方法上,也可以写到 Controller或 Controller 的方法上。
通常情况下都是写在控制器方法上的,控制接口URL是否允许被访问。
因为controller有对应的url,而如果写在service上,同一个service可以被不同的controller调用,比较难以控制
其实是先判断有没有登陆,如果登陆成功后还是没有权限才会报500,在此前我们没有权限是403
这些注解可以写到 Service 接口或方法上,也可以写到 Controller或 Controller 的方法上。
通常情况下都是写在控制器方法上的,控制接口URL是否允许被访问。
因为controller有对应的url,而如果写在service上,同一个service可以被不同的controller调用,比较难以控制
注解方式和配置类方式只能二选一
@Secured
专门用于判断是否具有角色的。能写在方法或类上
注意区分什么时候参数要加ROLE_:大小写依然严格区分
基于注解@Secured的value属性要以 ROLE_开头
基于注解@PreAuthorize的access表示式:可以加ROLE_也可以不加
基于配置类access表示式的一定不能加ROLE_
基于注解@Secured的value属性要以 ROLE_开头
基于注解@PreAuthorize的access表示式:可以加ROLE_也可以不加
基于配置类access表示式的一定不能加ROLE_
@PreAuthorize
表示访问方法或类在执行之前先判断权限,
大多情况下都是使用这个注解,
注解的参数和access()方法参数取值相同,都是权限表达式。
大多情况下都是使用这个注解,
注解的参数和access()方法参数取值相同,都是权限表达式。
@PreAuthorize
表示方法或类执行结束后判断权限,此注解很少被使用到
自定义403处理方案
实现 AccessDeniedHandler
字符输出流:PrintWriter getWriter()
这是response获取的字符流 在一次响应结束后会自动close和flush
这是response获取的字符流 在一次响应结束后会自动close和flush
设置头信息
application/json:返回json
charset避免中文乱码
application/json:返回json
charset避免中文乱码
//添加异常处理
http.exceptionHandling()
//推荐注入
.accessDeniedHandler(new MyAccessDeniedHandler());
http.exceptionHandling()
//推荐注入
.accessDeniedHandler(new MyAccessDeniedHandler());
RememberMe
导入依赖
配置数据源
MySQL时区问题:
UTC是是全球标准时间 ,
但是我们使用的时间是北京时区也就是东八区,领先UTC八个小时
为了remember配置自动建表里的时间字段与系统时间匹配
需要设置
serverTimezone=Asia/Shanghai
UTC是是全球标准时间 ,
但是我们使用的时间是北京时区也就是东八区,领先UTC八个小时
为了remember配置自动建表里的时间字段与系统时间匹配
需要设置
serverTimezone=Asia/Shanghai
编写配置
可以新建一个RememberMe的配置类
来注入数据源和设置jdbcTokenRepository相关配置
也可以直接写在SecurityConfig里
来注入数据源和设置jdbcTokenRepository相关配置
也可以直接写在SecurityConfig里
persistent_logins表里的字段
last_userd最新一次重新输入用户名密码登陆的时间,重新登陆会新增一条数据
token过期后,再尝试免登陆会报错,再清空该条数据
token过期后,再尝试免登陆会报错,再清空该条数据
修改SecurityConfig
添加RememberMeConfig和UserDetailsService实现类对象,并自动注入。
在 configure 中添加http.rememberMe()
在 configure 中添加http.rememberMe()
登陆页面添加复选框
注意标签name默认值是remember-me
如果修改了,
需要http.rememberMe().rememberMeParameter("标签名")
如果修改了,
需要http.rememberMe().rememberMeParameter("标签名")
有效时间
不修改配置情况下默认是2周
但是可以通过设置状态有效时间
.tokenValiditySeconds(60)
计时是从关闭浏览器开始持续的时间,
如果设置了60s,关闭浏览器30s后重新打开再关闭浏览器会重新计时
但是可以通过设置状态有效时间
.tokenValiditySeconds(60)
计时是从关闭浏览器开始持续的时间,
如果设置了60s,关闭浏览器30s后重新打开再关闭浏览器会重新计时
退出登陆
实现
实现非常简单
点击退出后默认跳转路径是/login.html?logout
点击退出后默认跳转路径是/login.html?logout
不使用默认值,修改配置
退出默认销毁 HttpSession 对象和清除认证状态
其他方法(一般不用)
addLogoutHandler(LogoutHandler)
clearAuthentication(boolean)
invalidateHttpSession(boolean)
logoutSuccessHandler(LogoutSuccessHandler)
CSRF/CORS
CSRF
刚开始学习Spring Security时,在配置类中一直存在这样一行代码:http.csrf().disable();
如果没有这行代码导致用户无法被认证。这行代码的含义是:关闭 csrf 防护
如果没有这行代码导致用户无法被认证。这行代码的含义是:关闭 csrf 防护
为什么需要CSRF
Token相对cookie的优势
无状态
前端表单通过隐藏域拿到token
CORS
JWT
Spring Security Oauth2 整合JWT
0 条评论
下一页