背景
在微服务中使用过SaToken的朋友可能跟我一样遇到了这样的问题。在无web上下文的情况下(定时任务、不与前端交互独立计算服务)调用服务间接口,由于没有token信息,调用接口时难以越过SaToken的权限认证体系。今天,我在xxljob中调用其他服务上面的接口就遇到了这个问题。
思路
本来想着自己在后端生成一个长期的token,供服务间调用使用。后来觉得麻烦,于是在拦截feign请求的拦截器上对请求headers做了处理,传了个“特殊的token”,这个特殊的token可以根据自己的想法去实现。总之这个token伴随请求达到具体的微服务模块时,在SatToken的认证拦截器里面做个判断,如果判断为是,则不需要进行权限认证。
实现
一、改造feign请求拦截器
public class FeignInterceptor implements RequestInterceptor {
/**
* 为 Feign 的 RCP调用 添加请求头Same-Token 和token
*
* @param requestTemplate
*/
@Override
public void apply(RequestTemplate requestTemplate) {
// SaSameToken 主要用于实现网关统一请求。即请求不能绕过网关去访问某个具体的服务
requestTemplate.header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken());
try {
// 当存在web上下文的时候,就正常在请求里面塞进去登录的时候申请到的token
requestTemplate.header(***monConstants.TOKEN_NAME, ***monConstants.TOKEN_PREFIX + StpUtil.getTokenValue());
} catch (Exception e) {
//在无web上下文的情况下,上面try里面的获取用户token的方法StpUtil.getTokenValue()会抛出错误,
//这里将抛出异常视为无web上下文的情况。无web上下文的时候,token的值赋值为SaSameToken的值,
//这个情况下,token的值可以通过自己的想法去赋值,不一定与我的想法一致。
requestTemplate.header(***monConstants.TOKEN_NAME, SaSameUtil.getToken());
}
}
}
二、重写认证方法
@Configuration(proxyBeanMethods = false)
public class SecurityConfiguration implements WebMv***onfigurer {
/**
* 注册sa-token的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注解拦截器,该拦截器(SaInterceptor)实现了注解式权限的检查。判断用户是否拥有访问接口所申明的权限
// 该拦截器有官方实现,我们要做的是重写一个拦截器,记得要继承官方的拦截器,
// 重写他的 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}
下面是重写SaInterceptor拦截器的preHandle方法(我自己定义的拦截器跟官方的拦截器名称一致,大家注意啊。要是不一样的话,addInterceptors()方法里面的拦截器名称记得换成你自己定义的名字,不要整半天没生效来骂我啊/)
@***ponent
@Primary
public class SaInterceptor extends ***.dev33.satoken.interceptor.SaInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
// 如果请求的header里面的SA-SAME-TOKEN 值和Authorization 值一样,就视为是内部接口调用,就直接返回ture
// 不在进行认证的相关逻辑。为什么相等时就视为是内部接口调用呢?请看上面的第一部分的feign拦截器的写法。
String saSameId = request.getHeader("SA-SAME-TOKEN");
String token = request.getHeader("Authorization");
if(saSameId.equals(token)){
return true;
}
//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断
//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断
//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断
//下面的逻辑跟官方一模一样,我只加了上面两行代码和判断
if(this.isAnnotation && handler instanceof HandlerMethod) {
// 获取此请求对应的 Method 处理函数
Method method = ((HandlerMethod) handler).getMethod();
// 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权
if(SaStrategy.me.isAnnotationPresent.apply(method, SaIgnore.class)) {
return true;
}
// 注解校验
SaStrategy.me.checkMethodAnnotation.a***ept(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());
return false;
}
// 通过验证
return true;
}
}
如果该文章帮到了您,请记得点咋,谢谢/