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