微服务使用Sa-token鉴权

557 阅读2分钟

微服务使用Sa-token鉴权

为了统一多个系统的认证,选择了Sa-token来做鉴权、认证、授权、单点登录。


首先区分这几个名词

  • 认证:确认访客的身份。像身份证、账号密码、二维码等。
  • 授权:赋予访客指定范围的资源操作权限。像钥匙、门禁卡。
  • 鉴权:对声明的身份信息真实性进行确认。像门禁卡需要通过门禁卡识别器。
  • 权限控制:判断操作是否允许/禁止。像管理员和普通员工权限范围不一致。
    顺序:先认证、授权、鉴权、最后权限控制

简单架构图

image.png

方案实现

SpringGateway

  1. 依赖
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.34.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  1. 注册Sa-token全局过滤器
@Configuration
public class SaTokenConfig {
    /**
     * 注册Sa-Token全局过滤器
     */
    @Bean
    public SaReactorFilter getSaReactorFilter(IgnoreUrlsConfig ignoreUrlsConfig) {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")
                // 开放地址
                .addExclude("/favicon.ico")
                .addExclude("/admin/registerAdmin")
                // 鉴权方法:每次访问进入
                .setAuth(obj -> { SaRouter.match("/**")
                            .notMatch(ignoreUrlsConfig.getUrls())
                            .check(r->{
                                StpUtil.checkLogin();
                            });
                })
                // setAuth方法异常处理
                .setError(e -> {
                    // 设置错误返回格式为JSON
                    return SaResult.error(ResultCodeEnum.PERMISSION_NO_ACCESS.getMsg());
                })
                ;
    }
}
  • 白名单路径
@Data
@Component
@ConfigurationProperties(prefix="secure.ignore")
public class IgnoreUrlsConfig {
    private List<String> urls;
}

Auth 只要集成Sa-Token并实现登录接口即可,非常简单。

  • 实现在微服务之间传递token 原理就是在进行feign调用时将token塞入header头中。配置在发起调用方。
@Component
public class FeignRequestInterceptor {

    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor() {

        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1、使用RequestContextHolder拿到刚进来的请求数据
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (requestAttributes != null) {
                    //老请求
                    HttpServletRequest request = requestAttributes.getRequest();
                    if (request != null) {
                        //2、同步请求头的数据(主要是cookie)
                        //把老请求的cookie值放到新请求上来,进行一个同步
                        //String cookie = request.getHeader("Cookie");
                        String authorization = request.getHeader("Authorization");
                        template.header("Authorization",authorization);
                    }
                }
            }
        };
    }

}

参考资料