一.背景
公司之前的鉴权都是自研的,并未引入shiro或者spring security oauth2等成熟的开源框架。主项目使用的鉴权方式是利用session来鉴权,这样的好处是,在requestHeader中,用户不能直接获取到token或者相关信息,但是对于权限续期和采用分布式或微服务方案后的鉴权一直都处理不好,于是需要对权限模块进行重做。
二. 选型
目前市面上最流行的两个开源鉴权框架,shiro和spring security oauth2我都有使用过,不过两者都有各自不好的地方。
spring security oauth2:
- 细粒度鉴权方面没有
shiro好,其粒度到role,不能到permission,如果要做的更好需要扩展 - 验证码登录、微信小程序登录等实现起来较为麻烦,具体方案可参见另外一篇文章: spring security Oauth2验证码等多方式登录
- 需要单独部署一个
server服务,相对而言更浪费服务器资源 - 配置很反锁,重量级
shiro:
- 第三方鉴权需要自己去实现
- 对oauth2协议不支持,有些功能需要自己实现
- 不支持token的刷新机制
由于以上原因,决定基于两者实现一个简单易用的鉴权流程满足需求。
二.方案
1.请求拦截
通过Interceptor拦截器来拦截所有请求,拦截器配置如下
/**
*mvc配置
* @program: Mr1ght
*/
@Slf4j
@Configuration
public class MvcConfiguration {
@Bean
public WebMvcConfigurer webMvcConfigurer(RedisOptUtils redisOptUtils, RedisUtils<Object> redisUtils) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// jwt拦截器
registry
.addInterceptor(new JwtSignInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/doc.html", "/error"
, "/static/**" //静态资源
)
;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
};
}
}
2.鉴权
2.1 token续期
取消掉token本身的过期时间,而采用redis的key过期策略来替代。将token存入redis时,设置token在redis中的过期时间,用户每次访问接口,被拦截器拦截到后,都重置redis的key过期时长,这样就保证了用户在经常访问的时候,能够永不退出,一直保持登录状态。也能保证用户在很久不登录之后,让用户重新登录以保证用户的账号安全
2.2 无需登录接口
因为部分接口是不需要登录的,因此定义了注解FreePassage,将此注解写到类上,则这个类下的所有接口都不会进行权限校验,如果将此注解写到接口上,则对应接口无需权限即可访问
import java.lang.annotation.*;
/**
* 免登录
*/
@Target(value = {
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FreePassage {
}
2.3 用户密码修改toke失效
缓存用户信息的时候缓存用户密码,利用用户密码作为token的秘钥进行加密解密,这样保证用户修改密码后,能让其他token失效。同时也能保证用户的token的加解密秘钥有一定保密性,保障用户的账户安全。
JwtUtil部分代码

本文提出了一种结合Spring Security OAuth2和Shiro优点的自定义鉴权方案,该方案包括了请求拦截、细粒度权限控制、第三方鉴权等功能,旨在提供一种轻量级且灵活的鉴权解决方案。
最低0.47元/天 解锁文章
506

被折叠的 条评论
为什么被折叠?



