学习笔记
- 一、SpringSecurity 简介
- 二、创建测试项目
- 2.1、引入依赖
- 2.2、测试
- 三、SpringSecurity基本原理
- 3.1、过滤器链
- 3.1.1、FilterSecurityInterceptor
- 3.1.2、ExceptionTranslationFilter
- 3.1.3、UsernamePasswordAuthenticationFilter
- 3.2、过滤器加载过程
- 3.3、两个重要的接口
- 3.3.1、UserDetailsService
- 3.3.2、PasswordEncoder
- 四、用户认证
- 4.1、方法一:配置文件
- 4.2、方法二:配置类
- 4.3、方法三:自定义编写实现类
一、SpringSecurity 简介
Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是 Spring Security 重要核心功能。
SpringSecurity 特点:
- 和 Spring 无缝整合。
- 全面的权限控制。
- 专门为 Web 开发而设计。
- 旧版本不能脱离 Web 环境使用。
- 新版本对整个框架进行了分层抽取,分成了核心模块和 Web 模块。单独引入核心模块就可以脱离 Web 环境。
- 重量级。
自从有了 Spring Boot 之后,Spring Boot 对于 Spring Security 提供了自动化配置方案,可以使用更少的配置来使用 Spring Security。
因此,一般来说,常见的安全管理技术栈的组合是这样的:(只是一个推荐的组合而已,如果单纯从技术上来说,无论怎么组合,都是可以运行的)
- SSM + Shiro
- Spring Boot/Spring Cloud + Spring Security
二、创建测试项目
2.1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
编写controller
@GetMapping("/hello")
public String hello() {
return "hello security";
}
2.2、测试
访问http://localhost:8080/test/hello
就会需要认证
默认用户名:user
密码在控制台会输出
三、SpringSecurity基本原理
3.1、过滤器链
SpringSecurity本质是一个过滤器链
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.SecurityContextPersistenceFilter
org.springframework.security.web.header.HeaderWriterFilter
org.springframework.security.web.csrf.CsrfFilter
org.springframework.security.web.authentication.logout.LogoutFilter
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.session.SessionManagementFilter
org.springframework.security.web.access.ExceptionTranslationFilter
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
SpringSecurity过滤器链中有几个比较重要的过滤器
3.1.1、FilterSecurityInterceptor
是一个方法级的权限过滤器, 基本位于过滤链的最底部
源码getSecureObjectClass部分:
//此处说明 在这个之前还会有过滤器 当之前的过滤器放行了才会进行到这一步
//super.beforeInvocation(fi)表示查看之前的 filter 是否通过
InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
try {
//表示真正的调用后台的服务
filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, (Object)null);
3.1.2、ExceptionTranslationFilter
是个异常过滤器,用来处理在认证授权过程中抛出的异常
3.1.3、UsernamePasswordAuthenticationFilter
对/login 的 POST 请求做拦截,校验表单中用户名,密码
3.2、过滤器加载过程
- 使用SpringSecurity配置过滤器 DelegatingFilterProxy(在SpringBoot中已经自动配置了)
- 在FilterChainProxy.class中把配置的过滤器加载到过滤器链中
3.3、两个重要的接口
3.3.1、UserDetailsService
当什么也没有配置的时候,账号和密码是由Spring Security定义生成的。
而在实际项目中账号和密码都是从数据库中查询出来的。
所以我们要通过自定义逻辑控制认证逻辑。
如果需要自定义逻辑时,只需要实现UserDetailsService,接口即可
步骤:
- 创建类继承UsernamePasswordAuthenticationFilter,重写三个方法
- 创建类实现UserDetailservice 编写查询数据过程,返回User对象,这个User对象是安全框架提供对象
3.3.2、PasswordEncoder
// 表示把参数按照特定的解析规则进行解析
String encode(CharSequence rawPassword);
//表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。
//如果密码匹配,则返回 true;如果不匹配,则返回 false。
//第一个参数表示需要被解析的密码。第二个参数表示存储的密码。
boolean matches(CharSequence rawPassword, String encodedPassword);
// 表示如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回false。默认返回 false。
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
四、用户认证
4.1、方法一:配置文件
spring.security.user.name=admin
spring.security.user.password=admin
4.2、方法二:配置类
使用 方法二 时 方法一 失效
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()//认证信息存储到内存中
.withUser("lucy")//用户名
.password(new BCryptPasswordEncoder().encode("123"))//用户密码(加密)
.roles("admin");//每个用户都配置角色(不能为空)
}
@Bean
//configure需要用到加密方式但默认没有 需要在容器的创建一个
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
4.3、方法三:自定义编写实现类
config:
@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
Service:
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("super");
//TODO :从查询数据库返回users对象,得到用户名和密码,返回
return new User("mary", new BCryptPasswordEncoder().encode("123"), auths);
}
}