背景
在微服务中使用过SaToken的朋友可能跟我一样遇到了这样的问题。在无web上下文的情况下(定时任务、不与前端交互独立计算服务)调用服务间接口,由于没有token信息,调用接口时难以越过SaToken的权限认证体系。今天,我在xxljob中调用其他服务上面的接口就遇到了这个问题。
思路
本来想着自己在后端生成一个长期的token,供服务间调用使用。后来觉得麻烦,于是在拦截feign请求的拦截器上对请求headers做了处理,传了个“特殊的token”,这个特殊的token可以根据自己的想法去实现。总之这个token伴随请求达到具体的微服务模块时,在SatToken的认证拦截器里面做个判断,如果判断为是,则不需要进行权限认证。
实现
一、改造feign请求拦截器
publicclassFeignInterceptorimplementsRequestInterceptor{/**
* 为 Feign 的 RCP调用 添加请求头Same-Token 和token
*
* @param requestTemplate
*/@Overridepublicvoidapply(RequestTemplate requestTemplate){// SaSameToken 主要用于实现网关统一请求。即请求不能绕过网关去访问某个具体的服务
requestTemplate.header(SaSameUtil.SAME_TOKEN,SaSameUtil.getToken());try{// 当存在web上下文的时候,就正常在请求里面塞进去登录的时候申请到的token
requestTemplate.header(CommonConstants.TOKEN_NAME,CommonConstants.TOKEN_PREFIX+StpUtil.getTokenValue());}catch(Exception e){//在无web上下文的情况下,上面try里面的获取用户token的方法StpUtil.getTokenValue()会抛出错误,//这里将抛出异常视为无web上下文的情况。无web上下文的时候,token的值赋值为SaSameToken的值,//这个情况下,token的值可以通过自己的想法去赋值,不一定与我的想法一致。
requestTemplate.header(CommonConstants.TOKEN_NAME,SaSameUtil.getToken());}}}
二、重写认证方法
@Configuration(proxyBeanMethods =false)publicclassSecurityConfigurationimplementsWebMvcConfigurer{/**
* 注册sa-token的拦截器
*/@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){// 注解拦截器,该拦截器(SaInterceptor)实现了注解式权限的检查。判断用户是否拥有访问接口所申明的权限// 该拦截器有官方实现,我们要做的是重写一个拦截器,记得要继承官方的拦截器,// 重写他的 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法
registry.addInterceptor(newSaInterceptor()).addPathPatterns("/**");}}
下面是重写SaInterceptor拦截器的preHandle方法(我自己定义的拦截器跟官方的拦截器名称一致,大家注意啊。要是不一样的话,addInterceptors()方法里面的拦截器名称记得换成你自己定义的名字,不要整半天没生效来骂我啊/)
@Component@PrimarypublicclassSaInterceptorextendscn.dev33.satoken.interceptor.SaInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{try{// 如果请求的header里面的SA-SAME-TOKEN 值和Authorization 值一样,就视为是内部接口调用,就直接返回ture// 不在进行认证的相关逻辑。为什么相等时就视为是内部接口调用呢?请看上面的第一部分的feign拦截器的写法。String saSameId = request.getHeader("SA-SAME-TOKEN");String token = request.getHeader("Authorization");if(saSameId.equals(token)){returntrue;}//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断if(this.isAnnotation && handler instanceofHandlerMethod){// 获取此请求对应的 Method 处理函数Method method =((HandlerMethod) handler).getMethod();// 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权if(SaStrategy.me.isAnnotationPresent.apply(method,SaIgnore.class)){returntrue;}// 注解校验SaStrategy.me.checkMethodAnnotation.accept(method);}// Auth 校验this.auth.run(handler);}catch(StopMatchException e){// 停止匹配,进入Controller}catch(BackResultException e){// 停止匹配,向前端输出结果if(response.getContentType()==null){
response.setContentType("text/plain; charset=utf-8");}
response.getWriter().print(e.getMessage());returnfalse;}// 通过验证returntrue;}}
如果该文章帮到了您,请记得点咋,谢谢/
版权归原作者 程序员劝退师·咩 所有, 如有侵权,请联系我们删除。