- Spring Security入门基础
- 一,Spring Security的使用
- 1.1 基本术语
- 1.2 基本使用
- 1.2.1 引入依赖
- 1.2.2 配置文件
- 1.2.3 测试接口
- 1.3 过滤器链的15个过滤器
- 1.4 自定义用户认证 WebSecurityConfigurerAdapter
- 1.4.1 configure(HttpSecurity http)
- 1.4.2 configure(AuthenticationManagerBuilder auth)
- 1.4.3 configure(WebSecurity web)
- 1.4.4 自定义表单登录
SpringSecurity是一个强大的可高度定制的认证和授权框架,对于Spring应用来说它是一套Web安全标准。Spring Security注重于为java应用提供认证和授权功能。
OAuth2是用于授权的行业标准协议,为简化客户端开发提供类特定的授权流。
Resource owner(资源拥有者):拥有该资源的最终用户,有访问资源的账号密码。
Resource server(资源服务器):拥有受保护资源的服务器,如果请求包含正确的访问令牌,可以访问资源。
Client(客户端):访问资源的客户端,会使用访问令牌去获取资源服务器的资源,可以是浏览器,移动设备或者服务器。
Authorization server(授权服务器):用于授权用户的服务器,如果客户端授权通过,发放访问资源服务器的令牌。
四种授权模式:
-
Authorization Code(授权码模式):客户端先将用户导向授权服务器,登陆后获取授权码,然后进行授权,最后根据授权码获取访问令牌。
-
Implicit(简化模式):和授权码模式相比,取消了获取授权码的过程,直接获取访问令牌。
-
Resource Owner Password Credential(密码模式):客户端直接向用户获取用户名和密码,之后向授权服务器获取访问令牌。
-
Client Credential(客户端模式):客户端直接通过客户端授权,从授权服务器获取访问令牌。
新创建模块tools-security,引入依赖:
1.2.2 配置文件org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security
server:
port: 9040
spring:
application:
name: tools-security
1.2.3 测试接口
@RequestMapping("test")
public String test() {
return "test";
}
运行项目,在以下截取的部分日志中,找到 Using generated security password,后面的字符串为原始密码(每次运行结果不同),账号为 user
2021-10-23 15:52:58.472 WARN [tools-security,,] 100588 --- [ restartedMain] o.s.c.s.a.z.ZipkinAutoConfiguration : Check result of the [RestTemplateSender{http://localhost:9411/api/v2/spans}] contains an error [CheckResult{ok=false, error=org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request: [Empty JSON_V2 message]}]
2021-10-23 15:52:59.049 INFO [tools-security,,] 100588 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-10-23 15:52:59.303 INFO [tools-security,,] 100588 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: 0c731ade-806a-4a8e-83e1-e11044fe0f48
访问 http://localhost:9040/test , 会先跳到默认的登录页面,输入账号(user)密码(0c731ade-806a-4a8e-83e1-e11044fe0f48)即可进行访问到 /test 接口。
1.3 过滤器链的15个过滤器1. org.springframework.security.web.context.SecurityContextPersistenceFilter
首当其冲的一个过滤器
SecurityContextPersistenceFilter主要是使用SecurityContextRepository在session中保存或更新一个securityContext,并将SecurityContext给以后的过滤器使用,来为后续Filter建立所需的上下文。
2. org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
此过滤器用于集成SecurityContext到Spring异步执行机制中的WebAsyncManager
3. org.springframework.security.web.header.HeaderWriterFilter
向请求的Header中添加相应的信息,可在http标签内部使用security:headers来控制
4. org.springframework.security.web.csrf.CsrfFilter
csrf又称跨域请求伪造,SpringSecurity会对所有post请求验证是否包含系统生成的CSRF的token信息,如果不包含,则报错。起到防止CSRF攻击的效果。
5. org.springframework.security.web.authentication.logout.LogoutFilter
匹配URL为/logout的请求,实现用户退出,清除认证信息。
6. org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
认证操作全靠这个过滤器,默认匹配URL为/login且必须为post请求。
7. org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面
8. org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
由此过滤器可以生产一个默认的退出登录页面
9. org.springframework.security.web.authentication.www.BasicAuthenticationFilter
此过滤器会自动解析http请求中头部名字为Authentication,且以Basic 开头的头信息。
10. org.springframework.security.web.savedrequest.RequestCacheAwareFilter
通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存HttpServletRequest
11. org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
针对ServletRequest进行了一次包装,使得request具有更加丰富的API
12. org.springframework.security.web.authentication.AnpnymousAuthenticationFilter
当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中。
spring security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
13. org.springframework.security.web.session.SessionManagementFilter
SecurityContextRepository限制同一用户开启多个回话的数量
14. org.springframework.security.web.access.ExceptionTranslationFilter
异常转移过滤器位于整个SpringSecurityFilterChain的后方,用来转换整个链路中出现的异常。
15. org.springframework.security.web.access.intercept.FilterSecurityinterceptor
1.4 自定义用户认证 WebSecurityConfigurerAdapter获取所配置资源访问的授权信息,根据SecurityContextHolder中存储的用户信息来决定其是否有权限
前面的做法是使用默认账号user和应用启动时自动生成的密码进行访问认证。但是,每个系统都应该有自己的用户体系,需要自定义用户的登录认证和接口的认证控制,这里就需要对WebSecurityConfiguration进行配置,主要关注三个方法:configure(HttpSecurity http),configure(AuthenticationManagerBuilder auth)和configure(WebSecurity)。
- HttpSecurity 允许基于选择匹配在资源级配置基于网络的安全性,并声明任何其他网址需要成功验证。也就是对角色的权限——所能访问的路径做出限制。
- AuthenticationManagerBuilder 用于通过允许AuthenticationProvider容易地添加来建立认证机制。配置的是认证信息 主要配置用户身份和角色信息也就是说用来记录账号,密码,角色信息。
- WebSecurity 用于影响全局安全性(配置资源,设置调试模式,通过实现自定义防火墙定义拒绝请求)的配置设置。一般用于配置全局的某些通用事物,例如静态资源等。
创建WebSecurityConfiguration.java,继承WebSecurityConfigurerAdapter
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
}
1.4.1 configure(HttpSecurity http)
HttpSecurity 有重要的两个方法authorizeRequests()和requestMatchers()
authorizeRequests()
授权管理控制的方法
这个方法返回一个expressionUrlAuthorizationConfigurer.expressionInterceptUrlRegistry对象。
authorizeRequests定义那些url需要被保护,那些不需要进行保护,通常出来在配置的第一行。
Security所有的权限控制都基于这个类进行控制。如:
http.authorizeRequests().anyRequest().authenticated()要求所有接口都需要进行权限认证,等同于http.authorizeRequests().antMatchers(" @Configuration public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/403", "/404", "/500").permitAll() // 访问403/404/500时不需要认证 .anyRequest().authenticated() // 其他请求需要认证 .and() .formLogin() // 通过form进行登录 .and() .csrf().disable(); // 关闭跨站请求伪造保护 } }
在以上配置中,我定义了请求为/403,/404和/500的三个接口不需要接受认证,直接放行;然后其他请求都需要认证;然后登录时要使用form方式,同时关闭跨站请求伪造保护。
在配置之前,我已经创建了403/404/500三个页面
@Controller public class PageController { @RequestMapping("403") public String accessError() { return "403"; } @RequestMapping("404") public String notFound() { return "404"; } @RequestMapping("500") public String serverError() { return "500"; } }此时,运行项目,访问 /404 接口能正常访问,然后访问 /test 接口时,会跳到Spring Security默认登录页面,输入账号密码后才放行。
1.4.2 configure(AuthenticationManagerBuilder auth)使用自定义用户密码登录(内存方式)
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() // 在内存存储用户信息 .withUser("lmc").password("{noop}123") // 用户名为lmc,密码为123,{noop}表示密码不加密 .roles("USER"); // 给用户lmc赋予USER角色 }spring security默认使用密码是需要加密的,即.password(String)里的密码已经是加密过的字符串,如果在前面加上{noop},就表示非加密的密码
.withUser("lmc").password("{noop}123") 也可以写成 .passwordEncoder(new BCryptPasswordEncoder()).withUser("lmc").password(new BCryptPasswordEncoder().encode("123"))注意,在security5.0之前默认加密方式是BC,所以只需要写成
.withUser("lmc").password(new BCryptPasswordEncoder().encode("123"))就可以,但是5.0后加密方式要自己定义,所以需要使用 passwordEncoder() 方法来定义加密方式,否则会报出以下异常:
There is no PasswordEncoder mapped for the id "null"1.4.3 configure(WebSecurity web)配置静态资源,忽略认证
@Override public void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/assets } .grid-content { border-radius: 4px; min-height: 36px; height: 800px; } .row-bg { padding: 10px 0; background-color: #f9fafc; } .el-card { padding: 80px; height: 638px; }lmc-tools 登录 Copyright © 2021 lmc


