当前位置: 首页 > article >正文

SpringCloud SaToken整合微服务 集成Redis 网关路由权限拦截 服务间内部调用鉴权

介绍

作为 API 网关,通常负责路由、负载均衡、安全控制等功能。进行 统一鉴权 的做法意味着将所有微服务的认证和授权逻辑集中到网关层,而不是每个微服务单独实现。这样做有许多好处,微服务只关心核心业务逻辑,不需要处理身份验证、权限验证等安全问题,减少了开发人员的负担。网关可以统一处理多种认证方式,如 JWT、OAuth 2.0、Basic Auth、API Key 等,灵活配置不同的认证机制。

微服务模块介绍

gateway-service:网关模块 包括:负载均衡 路由拦截 权限校验
user-service :用户模块 包括:用户登录 获取个人信息 等
goods-service:购物车模块 获取商品信息 搜索

全局POM依赖

以下配置需要在全部微服务中进行引入

 <!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:https://sa-token.cc -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
        <version>1.39.0</version>
    </dependency>

    <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-redis-jackson</artifactId>
        <version>1.39.0</version>
    </dependency>

 <!-- Sa-Token工具 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>

全局配置文件 集成Redis

以下配置需要在全部微服务中进行引入

spring:
  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:
  # token 有效期(单位:秒) 默认30天,-1 代表永久有效
  timeout: 2592000
  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
  active-timeout: 10
  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
  is-share: true
  # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
  token-style: uuid
  # 是否输出操作日志
  is-log: true

网关微服务

配置文件

server:
spring:    
  application:
    name: gateway #服务名称
  cloud:
    nacos:
      server-addr: 172.23.4.128:8848 #注册中心
    gateway:
      routes:
        - id: java-user #路由ID 一般为服务名称
          uri: lb://java-user #转发的路径 lb为负载均衡 java-user为服务接口
          predicates: #路由条件
            - Path=/user/** #请求接口路径
            # - Path=/user/**,/path/**    多个控制器这样写
        - id: java-goods
          uri: lb://java-goods
          predicates:
            - Path=/goods/**

全局过滤器

网关对所有的请求进行拦截

/**
 * [Sa-Token 权限认证] 配置类
 * @author click33
 */
@Configuration
public class SaTokenConfigure {
    // 注册 Sa-Token全局过滤器
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")    /* 拦截全部path */
                // 开放地址
                .addExclude("/favicon.ico")
                // 鉴权方法:每次访问进入
                .setAuth(obj -> {
                    // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
                    SaRouter.match("/**", "/user/login", r -> StpUtil.checkLogin());

                })
                // 异常处理方法:每次setAuth函数出现异常时进入
                .setError(e -> {
                    return SaResult.error(e.getMessage());
                    //SaResult.error(e.getMessage())  可以修改成自己的
                })
                ;
    }
}

网关转发鉴权

网关通过权限校验后,会将请求转发到对应的微服务上,这时子微服务也会有相对于的权限校验需要把改用户的token一起转发,这样子微服务的权限校验才会通过。方法还很简单只需要在头发的头部添加SAME_TOKEN参数即可

/**
 * 全局过滤器,为请求添加 Same-Token
 */
@Component
public class ForwardAuthFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest newRequest = exchange
                .getRequest()
                .mutate()
                // 为请求追加 Same-Token 参数
                .header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken())
                .build();
        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(newExchange);
    }
}

用户微服务

spring:
  application:
    name: java-user #服务名称

登录接口

@RestController
@AllArgsConstructor
@RequestMapping("/user")
public class UserController {

    private  final  IUserService userService;

    @PostMapping("/login")
    public SaResult   login(@RequestBody User retUser){
        System.out.println("用户登录");
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone, retUser.getPhone())
                .eq(User::getPassword,retUser.getPassword());
        User user = userService.getOne(queryWrapper);

        if(user==null){
            return SaResult.error("账号或密码错误");
        }
        System.out.println(user);
        
        StpUtil.login(user.getId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        return SaResult.ok(tokenInfo.getTokenValue());

    }
}

商品微服务

spring:
  application:
    name: java-goods #服务名称

商品权限校验

/**
 * Sa-Token 权限认证 配置类
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册 Sa-Token 全局过滤器
    @Bean
    public SaServletFilter getSaServletFilter() {
        return new SaServletFilter()
                .addInclude("/**")
                .addExclude("/favicon.ico")
                .setAuth(obj -> {
                    // 校验 Same-Token 身份凭证     —— 以下两句代码可简化为:SaSameUtil.checkCurrentRequestToken();
                    String token = SaHolder.getRequest().getHeader(SaSameUtil.SAME_TOKEN);
                    SaSameUtil.checkToken(token);
                })
                .setError(e -> {
                    return "无访问权限";
                })
                ;
    }
}

如果通过网关转发,可以正常访问。如果直接访问子服务会提示:无效Same-Token:xxx

服务间内部调用鉴权

在微服务架构中,服务间调用鉴权是确保服务之间安全通信的一种机制,防止未经授权的访问。每当一个微服务调用另一个微服务时,都需要验证调用者的身份和权限。常见的服务间鉴权方式包括基于令牌的鉴权、API Key、OAuth2、JWT(JSON Web Token)等方式。

创建OpenFeignConfig请求拦截器

/**
 * feign拦截器, 在feign请求发出之前,加入一些操作 
 */
@Component
public class FeignInterceptor implements RequestInterceptor {
    // 为 Feign 的 RCP调用 添加请求头Same-Token 
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken());
        
        // 如果希望被调用方有会话状态,此处就还需要将 satoken 添加到请求头中
        // requestTemplate.header(StpUtil.getTokenName(), StpUtil.getTokenValue());
    }
}

OpenFeignConfig请求接口

被调用方的代码无需更改,保持启动测试即可

@FeignClient(
        name = "java-goods",                 // 服务名称
        configuration = FeignInterceptor.class      // 请求拦截器 (关键代码)
)
public interface GoodsClient {

    @GetMapping("/goods/list")
    List<Goods> list();

//    List<Goods> list(@RequestParam("ids") List<Long> ids);
//传承就这样写

}

http://www.kler.cn/a/405824.html

相关文章:

  • 自动驾驶3D目标检测综述(三)
  • Vue实训---2-路由搭建
  • STM32完全学习——使用标准库点亮LED
  • 微信小程序混合 h5 wx.miniProgram是 undefined
  • 版本控制和idea简体中文教程
  • 堆优化版本的Prim
  • 状态模式之状态机
  • Linux进阶:环境变量
  • 2024年Java面试题及答案整理(1000+面试题附答案解析)
  • 【openwrt】Openwrt系统的reboot流程
  • 解决Flink读取kafka主题数据无报错无数据打印的重大发现(问题已解决)
  • React前端框架有哪些?
  • Go语言中的条件变量:sync.NewCond
  • 人工智能(AI)与机器学习(ML)基础知识
  • 14 go语言(golang) - 并发编程goroutine和channel
  • java http body的格式 ‌application/x-www-form-urlencoded‌不支持文件上传
  • 【C#设计模式(13)——代理模式(Proxy Pattern)】
  • vue生命周期 (创建阶段 | 挂载阶段 | 更新阶段 | 销毁阶段 )
  • http 流量接入 Dubbo 后端服务
  • 系统调用介绍