背景
当我们使用 Spring 技术栈搭建单体的系统或服务时,若系统涉及到登录鉴权等功能,一般会使用 SpringSecurity 搭配一个 RBAC 的权限模型,很容易实现一套 OAuth2 鉴权、授权的流程。
随着业务扩展,单体的服务作为一个微服务并入一个大的系统之后。我们为保证其他业务能够调用该单体服务,但是又无法让其他系统来使用该服务已有鉴权,从而引入其他微服务都用基础的鉴权服务。根据业务场景的区分,当单体服务内部使用的时候走 SpringSecurity 的鉴权,单体服务外部调用的时候使用基础鉴权服务鉴权。
基础
要根据不同的场景启用或绕过 SpringSecurity。我们可以首先想到能否通过 URL 来区分不同的场景,使用 HttpSecurity
的 permitAll()
和 authenticated()
来让不同路径的接口是否需要走鉴权。除此之外,可以去修改 SpringSecurity 的 Filter ,使用自定义 Filter 或者用动态代理对 Filter 进行增强。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| @Aspect @Component @Slf4j public class AuthorizationHeaderAspect {
@Autowired private OauthFeignBiz oauthFeignBiz;
@Pointcut("execution(* org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter(..))") public void securityOauth2DoFilter() { }
@Pointcut("execution(* org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(..))") public void securitySecurityInterceptor2DoFilter() {
}
@Around("securityOauth2DoFilter()") public void enhanceSecurityOauth2DoFilter(ProceedingJoinPoint joinPoint) throws Throwable { Object[] args = joinPoint.getArgs(); if (args == null || args.length != 3 || !(args[0] instanceof HttpServletRequest && args[1] instanceof javax.servlet.ServletResponse && args[2] instanceof FilterChain)) { joinPoint.proceed(); return; }
HttpServletRequest request = (HttpServletRequest) args[0]; String accessToken = request.getHeader("Authorization");
if (StringUtils.isNotBlank(request.getParameter("sceneId")) && StringUtils.isNotBlank(request.getParameter("sceneType"))) { SecurityUtils.setBaseAuth(true); } else { SecurityUtils.setBaseAuth(false); }
if (SecurityUtils.isBaseAuth()) { Response<CheckTokenResponse> checkTokenResponse = oauthFeignBiz.checkToken(accessToken); if (checkTokenResponse.getCode() == 0) { SecurityUtils.setBaseAuth((true)); ((FilterChain) args[2]).doFilter((ServletRequest) args[0], (ServletResponse) args[1]); } else { throw new Exception("鉴权失败"); } } else { joinPoint.proceed(); } }
@Around("securitySecurityInterceptor2DoFilter()") public void enhanceSecuritySecurityInterceptor2DoFilter(ProceedingJoinPoint joinPoint) throws Throwable { Object[] args = joinPoint.getArgs(); if (args == null || args.length != 3 || !(args[0] instanceof HttpServletRequest && args[1] instanceof javax.servlet.ServletResponse && args[2] instanceof FilterChain)) { joinPoint.proceed(); return; }
if (!SecurityUtils.isBaseOauth()) { joinPoint.proceed(); return; } ((FilterChain) args[2]).doFilter((ServletRequest) args[0], (ServletResponse) args[1]); }
}
|