关于SpringSecurity的一些使用心得

前段时间做了一个springsecurity为权限框架的单体springboot项目,时间过去许久,趁着周末闲暇时间,回忆总结一下。

最开始要做权限,因为是单体项目,首先就想到了shiro,但是由于shiro在前后端分离中出现的各种问题,(跨域携带cookie问题,前后端同时做处理解决后,一级域名不同仍然无法携带,明明设置了cookie,但是就是找不到,请求的时候也带不上,查看Set-Cookie这一行,有个黄色的叹号,chrome给的提示,因为SameSite设置的原因,chrome认为这个cookie不应该被跨越携带)

之后就果断转springSecurity了。

说起springsecurity也算是大名鼎鼎了,和springboot集成比较方便,先引坐标

<dependency>  
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

当你引入坐标的同时,security就会生效,访问接口会跳转到默认登录页面,security我理解是一个过滤链的形式,不同的”过滤器“具有不同的功能。

继承WebSecurityConfigurerAdapter,重写configure方法,写入自己的拦截路径等配置

继承OncePerRequestFilter这是一条重要的“过滤链”,重写自己的授权过滤逻辑,比如一些是否登录验证、token非法或过期验证等等。加入到configure的HttpSecurity中

实现UserDetails,用来装用户登录信息以及权限列表,需要注意的是,getAuthorities方法需要返回的是权限列表重写方法要返回true,这是一些额外功能,比如账户是否过期?是否禁用等等,自己根据业务更改即可。

实现UserDetailsService,重写登录的时候认证逻辑,同时把用户信息以及权限信息返回。

在WebSecurityConfigurerAdapter上面加上改注解@EnableGlobalMethodSecurity(prePostEnabled = true)开启授权功能,而OncePerRequestFilter便是授权的实现者之一。同时在其中加入Bean–passwordEncoder,可以return自带的加密BCryptPasswordEncoder,也可以自定义。

需要注意的点:

security所需的权限列表是一个List类型的数据,需要自己转换一下,比如:

List<GrantedAuthority> authorities = Arrays.asList("getInfo").stream().
                map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());

保存用户的时候,密码可以使用security的加密方式存储:

new BCryptPasswordEncoder().encode(personEntity.getPassword())

可以选择使用redis,在登录认证的时候一次查询数据库,把登录用户以及权限列表缓存,提高系统反应时间。

自定义失败处理,分别实现AccessDeniedHandler重写handle方法和AuthenticationEntryPoint重写commence方法,上面这两个分别是认证以及授权失败的异常处理类,交给HttpSecurity处理即可

跨域问题,先对springboot进行处理,webmvcconfigurer中允许跨域

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
      // 设置允许跨域的路径
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                // 是否允许cookie
                .allowCredentials(true)
                // 设置允许的请求方式
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                // 设置允许的header属性
                .allowedHeaders("*")
                // 跨域允许时间
                .maxAge(3600);
    }
}

再从springsecurity允许跨域:(在WebSecurityConfigurerAdapter的实现类中)

 HttpSecurity.cors(); //允许跨域