SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能

版本:

  • Springboot3.0.5以及对应的Springcloud,SpringcloudAlibaba依赖
  • nacos 2.2.0,sa-token1.34.0,Mysql8.0

前提:

  • 我这边是主要是对管理员进行鉴权的,所以划分了管理员以及网关服务,而sa-token的统一鉴权是在网关服务里面设计的。
  • Sa-token官方网址:Sa-Token

父依赖:




    
        17
        
        3.0.0
        2022.0.0.0-RC1
        2022.0.1
    


    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.projectlombok
            lombok
            1.18.26
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            mysql
            mysql-connector-java
            8.0.31
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            org.springframework.cloud
            spring-cloud-starter-loadbalancer
        


        
        
            cn.dev33
            sa-token-dao-redis-jackson
            1.34.0
        
        
            org.apache.commons
            commons-pool2
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
    

    

        
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                ${mybatis-spring-boot-starter.version}
            

            
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                ${spring-cloud-alibaba.version}
                pom
                import
            


            
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring.cloud.dependencies}
                pom
                import
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


Admin服务子模块

 依赖


    
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.3.1
        


        
            com.alibaba
            druid-spring-boot-starter
            1.1.9
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        


        
        
            org.springframework.cloud
            spring-cloud-starter-bootstrap
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
        
            org.springframework.cloud
            spring-cloud-starter-loadbalancer
        
        
        
            cn.dev33
            sa-token-spring-boot3-starter
            1.34.0
        
        
        
            com.example
            commons
            0.0.1-SNAPSHOT
        
        
            io.projectreactor
            reactor-core
            3.5.4
        



    

 控制器类:按照官方文档,我们知道只需要实现它的StpUtil.login(Object id); 方法就行。

@RestController
@RequestMapping("/admin")
public class AdminController{
    @Resource
    AdminService adminService;


    @PostMapping("/login")
    public R login(@RequestParam("id") int id,
                   @RequestParam("password") String password)
    {
        Admin admin=adminService.login(id,password);
        if(!ObjectUtils.isEmpty(admin))
        {
//            登录
            StpUtil1.setStpLogic(new StpLogic("admin"));
            StpUtil1.login(admin.getId());
//            获取token并返回
            return   R.success("登录成功",StpUtil1.getTokenInfo());
        }
        return R.error("登录失败");
    }

上面我用的是StpUtil1而不是StpUtil ,原因是我系统有两个角色超级管理员管理员,所以根据官方文档我创建了一个新的类,叫做StpUtil1,然后将其StpUtil复制过来,更改其属性TYPE为admin 。同理超级管理员也是创建多一个类就行,更改TYPE,这让我想起了设计模式的开闭原则哈哈哈。

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第1张图片

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第2张图片

        配置文件bootstrap.yml,因为配置数据库的配置在配置中心,这里就不放出来了

Redis整合

这里sa-token整合redis只需要将配置文件配置,和导入依赖,sa-token就会自动将数据存入redis里面了,注意版本要对上,以防错误。

server:
  port: 8081
spring:
  application:
    name: Admin-service
  profiles:
    # 环境也是和配置文件保持一致
    active: db
  cloud:
    nacos:
      config:
        # 配置文件后缀名
        file-extension: yml
        # 配置中心服务器地址,也就是Nacos地址
        server-addr: localhost:8848
        prefix: dataBase
      discovery:
        # 配置Nacos注册中心地址
        server-addr: localhost:8848
  data:
  # redis配置
    redis:
      # Redis数据库索引(默认为0)
      database: 1
      # Redis服务器地址
      host: 127.0.0.1
      # Redis服务器连接端口
      port: 6379
      # Redis服务器连接密码(默认为空)
      # password:
      # 连接超时时间
      timeout: 10s
      lettuce:
        pool:
          # 连接池最大连接数
          max-active: 200
          # 连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
          # 连接池中的最大空闲连接
          max-idle: 10
          # 连接池中的最小空闲连接
          min-idle: 0

 Gateway服务子模块

依赖



    
        competition
        com.example
        0.0.1-SNAPSHOT
    
    4.0.0

    GateWay

    
        17
        17
    
    
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        
        
            cn.dev33
            sa-token-reactor-spring-boot3-starter
            1.34.0
        
        
            org.springframework.cloud
            spring-cloud-starter-bootstrap
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
        
            org.springframework.cloud
            spring-cloud-starter-loadbalancer
        

        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        
        
        
            org.springframework.boot
            spring-boot-starter-web
            test
        
        
        
            com.example
            commons
            0.0.1-SNAPSHOT
        
    

整合Gateway注意点

值得注意的是,因为Gateway是基于 WebFlux开发的,所以呢,我们需要去到官网,找一下下资料,如图,要导入的依赖是带有reactor的噢,而且因为使用的是springboot3,所以还要将boot改为boot3别导错依赖了!!

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第3张图片

 全局过滤器类(鉴权,登录拦截token,跨域)

  • SptUtil1和SptUtil2都是在公共模块commons中的哈,然后两者除了Type不一样其他都一样,用来区分不同管理员,超级管理员是拥有所有权限的,而管理员权限是超级管理员分配的。
  • 所以超级管理员只要登录就可以访问各个路径啦
  • 但是管理员就要检测一下权限了。看官网给出的详细代码解释SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第4张图片

package com.test.conf;


import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.test.entity.StpUtil1;
import com.test.entity.StpUtil2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


/**
 * @author LiYa
 * @create 2023-04-05 22:36
 */
@Configuration
public class SaTokenConfigure  {
    // 注册 Sa-Token全局过滤器

    @Bean
    @Primary
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter  ()
                // 拦截地址
                .addInclude("/**")
                // 开放地址
                .addExclude("/admin/login")
                .addExclude("/SuperAdmin/login")
                // 鉴权方法:每次访问进入
                .setAuth(obj -> {
                    System.out.println("---------- sa全局认证");
                    System.out.println(StpUtil1.isLogin());
                    System.out.println(StpUtil2.isLogin());
                    System.out.println(StpUtil1.getPermissionList());
                    // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
//                    SaRouter.match("/**", "/admin/login", r -> StpUtil1.checkLogin());
                    // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
                    // 权限认证 -- 不同模块, 校验不同权限
                    SaRouter.match("/events/**").check(r -> {
                       if(StpUtil1.hasPermission("mEvent")==false && StpUtil2.isLogin()==false)
                       {
                           throw new SaTokenException("没有权限噢");
                       }
                    });
                    SaRouter.match("/admin/**").check(r -> {
                        if(StpUtil2.isLogin()==false)
                        {
                            throw new SaTokenException("没有权限噢");
                        }
                    });
                    SaRouter.match("/advertisement/**").check(r -> {
                        if(StpUtil1.hasPermission("mAdvertisement")==false && StpUtil2.isLogin()==false)
                        {
                            throw new SaTokenException("没有权限噢");
                        }
                    });
                    SaRouter.match("/award/**").check(r -> {
                        if(StpUtil1.hasPermission("mAward")==false && StpUtil2.isLogin()==false)
                        {
                            throw new SaTokenException("没有权限噢");
                        }
                    });
                    SaRouter.match("/notice/**").check(r -> {
                        if(StpUtil1.hasPermission("mNotice")==false && StpUtil2.isLogin()==false)
                        {
                            throw new SaTokenException("没有权限噢");
                        }
                    });
                })
                // 异常处理方法:每次setAuth函数出现异常时进入
                .setError(e -> {
                    System.out.println("---------- sa异常认证");
                    return SaResult.error(e.getMessage());
                })
// 前置函数:在每次认证函数之前执行
        		.setBeforeAuth(obj -> {
            // ---------- 设置跨域响应头 ----------
            SaHolder.getResponse()
                    // 允许指定域访问跨域资源
                    .setHeader("Access-Control-Allow-Origin", "*")
                    // 允许所有请求方式
                    .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                    // 有效时间
                    .setHeader("Access-Control-Max-Age", "3600")
                    // 允许的header参数
                    .setHeader("Access-Control-Allow-Headers", "*");

            // 如果是预检请求,则立即返回到前端
            SaRouter.match(SaHttpMethod.OPTIONS)
                    .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
                    .back();
        });
    }

}

那么管理员的权限从哪来呢?不用思考直接看官网。

只要实现了这个接口,就可以设计权限了,ohyeah,真的太腻害了 !

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第5张图片但值得注意的是,因为采用的是Springcloud,所以不能在admin服务那边实现该接口,必须要在网关服务里面实现,否则是没有的!!!!!!!空说无凭,上证据,看官网

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第6张图片

 实现StpInterface 接口的代码(在网关服务里面实现)

package com.test.auth;

import cn.dev33.satoken.stp.StpInterface;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author LiYa
 * @create 2023-04-09 16:50
 * 通过前端传递过来的token可以找到该logintype对应的id
 */
@Component
public class stp implements StpInterface {
    @Resource
    RedisTemplate redisTemplate;


    @Override
    public List getPermissionList(Object loginId, String loginType) {

        return (List) redisTemplate.opsForList().range(loginType+loginId, 0,-1);
    }

    @Override
    public List getRoleList(Object loginId, String loginType) {
        List list =new ArrayList<>();
        list.add(loginType);
        return list;
    }
}

bootstrap.yml 

server:
  port: 8500

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
      config:
        extension-configs:
          - data-id: Gateway-dev.yml
            group: DEFAULT_GROUP
            refresh: true

#          - data-id: intercept-dev.yml
#            group: DEFAULT_GROUP
#            refresh: true

  data:
    # redis配置
    redis:
      # Redis数据库索引(默认为0)
      database: 1
      # Redis服务器地址
      host: 127.0.0.1
      # Redis服务器连接端口
      port: 6379
      # Redis服务器连接密码(默认为空)
      # password:
      # 连接超时时间
      timeout: 10s
      lettuce:
        pool:
          # 连接池最大连接数
          max-active: 200
          # 连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
          # 连接池中的最大空闲连接
          max-idle: 10
          # 连接池中的最小空闲连接
          min-idle: 0

# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: satoken
  # token有效期,单位秒,-1代表永不过期
  timeout: 2592000
  # token临时有效期 (指定时间内无操作就视为token过期),单位秒
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: false
  # 是否从cookie中读取token
  is-read-cookie: false





接下来就是测试了,启动服务,访问登录,呐呐呐,看到返回值没有,我们这个时候就可以提取tokenValue和tokenName去访问服务了。

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第7张图片

访问redis成功出现数据 。

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第8张图片

此时我们去访问某个服务,先不带token访问,毫无疑问被拦截了

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第9张图片

设置token,yeah成功有数据返回啦

SpringCloud3.0+Sa-token+Gateway网关实现鉴权和token登录拦截功能_第10张图片


 总结:看官网,多实践,给博主点赞关注,这样就可以理解解决任何bug,最主要的还是多实践以及给博主点赞关注

你可能感兴趣的:(gateway,spring,cloud,spring,boot,java,maven)