SaToken实现微服务内部接口调用免认证(无web上下文的情况下)

背景

在微服务中使用过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(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)
public class SecurityConfiguration implements WebMvcConfigurer {

    /**
     * 注册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()方法里面的拦截器名称记得换成你自己定义的名字,不要整半天没生效来骂我啊/)

@Component
@Primary
public class SaInterceptor extends cn.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.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());
            return false;
        }

        // 通过验证
        return true;
    }

}

如果该文章帮到了您,请记得点咋,谢谢/

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Cloud微服务架构中,Nacos是一个注册中心和配置中心。Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加容易。 使用Feign调用接口需要以下步骤: 1. 在pom.xml中添加Feign依赖 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 在启动类上添加@EnableFeignClients注解启用Feign客户端 ```java @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 3. 创建接口,并使用@FeignClient注解指定调用的服务名称和服务路径 ```java @FeignClient(name = "service-provider") public interface UserService { @GetMapping("/user/{id}") String getUserById(@PathVariable("id") Long id); } ``` 其中,name属性指定服务名称,GetMapping注解指定服务路径。 4. 在需要使用该服务的地方注入UserService并调用方法即可 ```java @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/user/{id}") public String getUserById(@PathVariable("id") Long id) { return userService.getUserById(id); } } ``` 在这个例子中,我们定义了一个名为UserService的Feign客户端,指定了调用的服务名称和服务路径。然后在UserController中注入了UserService并调用了其方法。最终,Feign会自动将该请求转发到名为service-provider的微服务,并返回结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值