IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Cloud Gateway 集成Sa-Token -> 正文阅读

[Java知识库]Spring Cloud Gateway 集成Sa-Token

引言

Hello 大家好,这里是Anyin。

在我之前的文章中,不知道大家有没有发现我的代码都是放在Anyin Cloud这个项目的(欢迎大家点个星星)。这个项目我积累了一些我自己平时在工作当中小工具和最佳实践,随着时间的推进这个项目已经慢慢成为一个我个人搭建项目的脚手架,能够快速搭建起来一个完善的基于Spring Cloud技术栈的微服务基础架构。

之前在掘金上看到一个权限认证的框架Sa-Token,简单的了解下,发现确实容易上手,而且功能丰富。今天就让我们来把它集成到 Anyin Cloud项目吧。

需求梳理

在把Sa-Token集成到我们的项目之前,我们需要先梳理下需求,不能为了集成而集成。

  1. Anyin Cloud项目需要一个认证鉴权的框架,经过选型,确定使用Sa-Token
  2. Anyin Cloud项目是一个微服务项目,所以我们统一的认证需要放在认证服务Auth,而统一的鉴权是放在网关Gateway
  3. AuthGateway都是高频访问的服务,需要足够轻量,所以我们设计这两个服务都不依赖数据库,并且不会过多依赖其他服务,Auth服务和Gateway服务的数据通信通过Redis
  4. Gateway服务需要把当前登录用户的标识传递到下游。

Sa-Token集成

集成认证Auth服务

首先,我们先来处理Auth服务。

添加pom.xml依赖,因为我们需要通过Redis来进行数据通讯,所以需要依赖对应的Redis组件。

        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-dao-redis-jackson</artifactId>
        </dependency>
复制代码

Auth服务编写Login方法。按我们之前的需求,Auth需要足够轻量,所以它不会去依赖数据库,在登录的时候需要用户信息,通过用户服务upms远程调用从而获取用户信息。

@Component
@Slf4j
public class UsernameLoginHandler implements LoginHandler {
    @Autowired
    private SysUserFeignApi sysUserFeignApi;
    @Override
    public LoginTypeEnum extension() {
        return LoginTypeEnum.USERNAME;
    }
    @Override
    public LoginUserDTO login(String... content) {
        // TODO param check
        String username = content[0];
        String password = content[1];
        SysUserResp sysUser = sysUserFeignApi.infoByUsername(username).getData();
        if(sysUser == null){
            throw AuthExCodeEnum.USER_NOT_REGISTER.getException();
        }
        // TODO add salt
        if(!sysUser.getPassword().equals(SecureUtil.md5(password))){
            throw AuthExCodeEnum.USER_PASSWORD_ERROR.getException();
        }
        if(UserStatusEnum.DISABLE.getCode().equals(sysUser.getStatus())){
            throw AuthExCodeEnum.USER_IS_DISABLE.getException();
        }
        sysUser.setPassword(null);

        StpUtil.login(sysUser.getId());
        SaTokenInfo token = StpUtil.getTokenInfo();

        LoginUserDTO user = new LoginUserDTO();
        user.setSysUser(sysUser);
        user.setToken(token);
        return user;
    }
}
复制代码

根据Sa-Token建议的使用方式,在我们对用户密码进行校验正确之后,通过StpUtil.login来进行框架内部的登录操作,这个操作其实是在Redis上记录对应的信息。在Redis上会记录2个信息:

  • 用户ID,satoken:login:session:开头,它的值还会包含一些其他的信息
  • 登录的Token,satoken:login:token:开头,它的值就是用户ID

在登录之后,我们还需要获取token返回给前端,所以这里使用StpUtil.getTokenInfo()获取token信息,最后组装用户信息和token信息返回给前端。

代码编写好,我们需要对登录接口做下测试。

好了,登录的认证我们已经处理好了,简不简单?香不香 ?

集成鉴权Gateway服务

我们接着处理鉴权Gateway服务。老规矩,先添加依赖。

这里要特别注意了,因为我们的网关是Spring Cloud Gateway,底层是WebFlux实现,它是基于Reactor模型编程的;而之前的Auth服务是正常的SpringMVC服务,基于Servlet模型编程的。

所以我们这里引入的是sa-token-reactor-spring-boot-starter

        <!-- sa-token -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-dao-redis-jackson</artifactId>
        </dependency>
复制代码

接着,我们继续编写Gateway服务的过滤器,在过滤器中我们主要做以下3个事情:

  1. 判断哪些路由需要进行鉴权,哪些不需要。
  2. 如果需要鉴权,则判断是否登录,未登录则直接返回异常信息。
  3. 如果登录,则透传用户ID到下游服务

对于判断哪些路由需要鉴权,我们可以在动态路由中配置路由的元数据,从而判断当前路由是否鉴权。代码如下:

        Route route = (Route)exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        Integer needAuth =(Integer) route.getMetadata().get(GatewayConstants.SYS_ROUTE_AUTH_KEY);
        // 无需认证的路由
        if(!NEED_AUTH.equals(needAuth)){
            return chain.filter(exchange);
        }
复制代码

当路由需要进行鉴权的时候,我们再使用Sa-Token提供的isLogin方法进行判断,如果未登录则响应异常信息。如下:

        // 判断是否登录
        if(!StpUtil.isLogin()){
            return this.response(exchange, CommonExCodeEnum.USER_NOT_LOGIN.getException());
        }
复制代码

如果当前请求用户已经登录,则使用StpUtil.getLoginId方法获取当前用户ID,然后透传到下游服务,如下:

    private ServerWebExchange setHeaderLoginId(ServerWebExchange exchange, String loginId){
        ServerHttpRequest request = exchange.getRequest().mutate().header(CommonConstants.USER_ID, loginId).build();
        return exchange.mutate().request(request).build();
    }
复制代码

最后,很关键的一步,我们还需要注册全局的过滤器,除了我们自己编写的过滤器,还有Sa-Token的过滤器。如果细心的同学可以发现StpUtil工具类提供的方法都是很简单,得益于它需要注册一个全局的过滤器SaReactorFilter,通过该过滤器它把大量的上下文信息和对应的逻辑都在内部处理掉。所以,我们需要注册2个过滤器,如下:

    @Bean
    public GatewayAuthFilter gatewayAuthFilter(){
        return new GatewayAuthFilter();
    }
    @Bean
    public SaReactorFilter saReactorFilter(){
        return new SaReactorFilter();
    }
复制代码

其实SaReactorFilter过滤器提供了很多的方法和参数,用来处理各种业务场景,但是因为我这边可能需要对过滤器进行更加定制化的逻辑处理,所以未使用它内部的一些方法。

测试

完成了以上2部分代码,我们需要对其进行测试下,看看框架是否好事。

首先,测试下不传递token的场景,是否会报未登录的异常。

传递token的场景下,能够正常返回信息

最后

感谢Sa-Token作者提供了这么一个牛皮的框架。其文档地址 Sa-Token

以上,就是Spring Cloud Gateway集成Sa-Token的步骤,如果有什么问题,欢迎指正。
后面会深入Sa-Token源码,了解更多的使用方法和设计思想,敬请期待。


?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:50:24  更:2022-08-19 18:50:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:21:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码