Spring Security 介绍
Spring Security 应该属于 Spring 全家桶中学习曲线比较陡峭的几个模块之一,下面我将从起源和定义这两个方面来简单介绍一下它。
- 起源: Spring Security 实际上起源于 Acegi Security,这个框架能为基于 Spring 的企业应用提供强大而灵活安全访问控制解决方案,并且框架这个充分利用 Spring 的 IoC 和 AOP 功能,提供声明式安全访问控制的功能。后面,随着这个项目发展, Acegi Security 成为了Spring官方子项目,后来被命名为 “Spring Security”。
- **定义:**Spring Security 是一个功能强大且高度可以定制的框架,侧重于为Java 应用程序提供身份验证和授权。——官方介绍。
Session 和 Token 认证对比
Session 认证图解
很多时候我们都是通过 SessionID 来实现特定的用户,SessionID 一般会选择存放在 Redis 中。举个例子:用户成功登陆系统,然后返回给客户端具有 SessionID 的 Cookie,当用户向后端发起请求的时候会把 SessionID 带上,这样后端就知道你的身份状态了。
关于这种认证方式更详细的过程如下:
- 用户向服务器发送用户名和密码用于登陆系统。
- 服务器验证通过后,服务器为用户创建一个 Session,并将 Session信息存储 起来。
- 服务器向用户返回一个 SessionID,写入用户的 Cookie。
- 当用户保持登录状态时,Cookie 将与每个后续请求一起被发送出去。
- 服务器可以将存储在 Cookie 上的 Session ID 与存储在内存中或者数据库中的 Session 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。
Token 认证图解
在基于 Token 进行身份验证的的应用程序中,服务器通过Payload、Header和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端,客户端将 Token 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization字段中: Authorization: Bearer Token。
关于这种认证方式更详细的过程如下:
- 用户向服务器发送用户名和密码用于登陆系统。
- 身份验证服务响应并返回了签名的 JWT,上面包含了用户是谁的内容。
- 用户以后每次向后端发请求都在 Header 中带上 JWT。
- 服务端检查 JWT 并从中获取用户相关信息。
项目涉及到的重要类说明
配置类
在本项目中我们自定义 SecurityConfig 继承了 WebSecurityConfigurerAdapter。 WebSecurityConfigurerAdapter提供HttpSecurity来配置 cors,csrf,会话管理和受保护资源的规则。
配置类中我们主要配置了:
- 密码编码器 BCryptPasswordEncoder(存入数据库的密码需要被加密)。
- 为 AuthenticationManager 设置自定义的 UserDetailsService以及密码编码器;
- 在 Spring Security 配置指定了哪些路径下的资源需要验证了的用户才能访问、哪些不需要以及哪些资源只能被特定角色访问;
- 将我们自定义的两个过滤器添加到 Spring Security 配置中;
- 将两个自定义处理权限认证方面的异常类添加到 Spring Security 配置中;
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsServiceImpl userDetailsServiceImpl; /** * 密码编码器 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public UserDetailsService createUserDetailsService() { return userDetailsServiceImpl; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 设置自定义的userDetailsService以及密码编码器 auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(bCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and() // 禁用 CSRF .csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.POST, "/auth/login").permitAll() // 指定路径下的资源需要验证了的用户才能访问 .antMatchers("/api/**").authenticated() .antMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN") // 其他都放行了 .anyRequest().permitAll() .and()