[Spring Cloud] (3)gateway令牌token拦截器

文章目录

    • 集成redis
      • Nacos配置增加
    • redis配置
    • 配置pom
      • redis配置RedisConfig
      • redis序列化工具FastJson2JsonRedisSerializer
      • 测试
    • 令牌校验拦截器
      • nacos配置
      • 拦截器代码
      • 微服务登录接口实现
    • 最终效果-登录接口与数据接口

本文gateway与微服务已开源到gitee
杉极简/gateway网关阶段学习

在Gateway(网关)与微服务架构中,令牌校验器(Token Validator)通常扮演着至关重要的角色,它的作用主要包括:

  1. 身份验证:令牌校验器确保只有拥有有效令牌的用户或服务才能访问微服务。这是保护后端服务的第一道防线。
  2. 权限控制:令牌中可能包含了用户的权限信息,校验器可以检查用户是否有足够的权限来访问特定的资源或执行特定的操作。
  3. 会话管理:在用户与服务之间维护会话状态,确保用户在一段时间内的请求可以关联到同一个会话。
  4. 单点登录(SSO):如果多个微服务共享同一个认证系统,令牌校验器可以帮助实现单点登录,用户只需要登录一次就可以访问所有服务。
  5. 负载减轻:通过在网关层面校验令牌,可以减轻微服务的负担,因为微服务不需要再进行令牌的校验,可以专注于业务逻辑的处理。
  6. 安全性增强:令牌校验器可以确保令牌的传输和使用符合安全标准,比如使用HTTPS传输,确保令牌不被窃取或篡改。
  7. 跨域处理:在网关层面处理跨域资源共享(CORS)问题,确保来自不同域的请求能够正常访问微服务。
  8. 集中管理:通过在网关处统一校验令牌,可以集中管理认证策略和令牌格式,便于维护和更新。
  9. 监控与日志记录:在令牌校验的过程中,可以记录相关的访问日志,便于后续的监控和分析。

令牌校验器通常是集成在API网关中的一个组件,它作为微服务架构中的守门人,确保所有进入微服务网络的请求都是合法和安全的。

集成redis

Nacos配置增加

Nacos中增加如下配置

  redis:
    host: localhost
    port: 6379
    password: 123456
    timeout: 6000

image.png

redis配置

image.png

配置pom

<!--redis-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

redis配置RedisConfig

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * redis配置
 *
 * @author fir
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{
    @Bean
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        serializer.setObjectMapper(mapper);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);

        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}

redis序列化工具FastJson2JsonRedisSerializer

package com.fir.gateway.config.redis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;


/**
 * Redis使用FastJson序列化
 *
 * @author fir
 */
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{

    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    private final Class<T> clazz;


    public FastJson2JsonRedisSerializer(Class<T> clazz)
    {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException
    {
        if (t == null)
        {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException
    {
        if (bytes == null || bytes.length <= 0)
        {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);

        return JSON.parseObject(str, clazz);
    }

    public void setObjectMapper(ObjectMapper objectMapper)
    {
        Assert.notNull(objectMapper, "'objectMapper' must not be null");
    }

    protected JavaType getJavaType(Class<?> clazz)
    {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}


测试

通过一下代码进行测试,通过测试redis已经集成成功,详情如下:

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;



@SpringBootTest
public class RedisTest {



    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    @Test
    void set(){

        redisTemplate.opsForValue().set("name123", "value123");
    }

    @Test
    void get(){

        Object object = redisTemplate.opsForValue().get("name123");


        System.out.println(object);
    }
}

image.png

令牌校验拦截器

image.png

nacos配置

首先在nacos中新增tokenCheckwhiteUrls配置项**,**如下配置:

global:
  # 全局异常捕捉-打印堆栈异常
  printStackTrace: true
  # 令牌头变量名称
  token: Authorization
  # 令牌校验
  tokenCheck: true
  # 不需要进行过滤的白名单
  whiteUrls:
    - /tick/auth/login
    - /ws

拦截器代码

import com.fir.gateway.config.GlobalConfig;
import com.fir.gateway.config.exception.CustomException;
import com.fir.gateway.config.result.AjaxStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;


/**
 * 令牌token校验拦截器
 *
 * @author fir
 */
@Slf4j
@Component
public class AuthorizationFilter implements GlobalFilter, Ordered {


    /**
     * 网关参数配置
     */
    private GlobalConfig globalConfig;


    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public void someComponent(GlobalConfig globalConfig) {
        this.globalConfig = globalConfig;
    }


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("登录信息校验:start");
        // 判断token是否存在,且是否过期
        boolean tokenKey = globalConfig.isTokenCheck();
        if (tokenKey) {
            // 白名单路由判断
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getPath().toString();
            List<String> whiteUrls = globalConfig.getWhiteUrls();

            if (!whiteUrls.contains(path)) {
                String tokenHeader = globalConfig.getTokenHeader();
                String token = exchange.getRequest().getHeaders().getFirst(tokenHeader);

                if (token == null || token.isEmpty()) {
                    log.error("token为空");
                    throw new CustomException(AjaxStatus.EXPIRATION_TOKEN);
                }

                Object obj = redisTemplate.opsForValue().get(token);
                if (obj != null) {
                    log.info("登录信息校验:true");
                } else {
                    log.error("token已失效");
                    throw new CustomException(AjaxStatus.EXPIRATION_TOKEN);
                }
            } else {
                log.info("登录信息校验:true,白名单");
            }
        } else {
            log.info("登录信息校验:true,验证已关闭");
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -290;
    }
}

微服务登录接口实现

微服务同样需要集成redis,集成方式与gateway一样

package com.fir.nacos.controller;

import com.alibaba.nacos.common.utils.StringUtils;
import com.fir.nacos.config.result.AjaxResult;
import com.fir.nacos.config.result.AjaxStatus;
import com.fir.nacos.entity.LoginResultDTO;
import com.fir.nacos.service.IAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;


/**
 * @author fir
 */
@Slf4j
@Api(tags = "系统接口")
@RestController
@RefreshScope
@RequestMapping("/auth")
public class AuthController {


    @Resource
    private IAuthService iAuthService;

    /**
     * 用户统一登陆
     *
     * @param username 用户
     * @param password 密码
     * @return 登录信息/登录失败信息
     */
    @ApiOperation("登录接口")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "username", value = "用户"),
        @ApiImplicitParam(name = "password", value = "密码")
    })
    @RequestMapping("/login")
    public AjaxResult login(String username, String password) {
        LoginResultDTO loginResultDTO;
        if(StringUtils.isNoneBlank(username) && StringUtils.isNoneBlank(password)){
            loginResultDTO = iAuthService.login(username, password);
        }else {
            return AjaxResult.error(AjaxStatus.NULL_LOGIN_DATA);
        }
        return AjaxResult.success(loginResultDTO);
    }
}
/**
     * 用户统一登录
     *
     * @param username 账号
     * @param password 密码
     * @return 登录信息
     */
@Override
public LoginResultDTO login(String username, String password){
    LoginResultDTO loginResultDTO = new LoginResultDTO();
    if(StringUtils.isNoneBlank(username) && StringUtils.isNoneBlank(password)){
        // 此处简单处理,根据实际的项目做更改
        if(username.equals("fir") && password.equals("123456")){


            // 生成 Token (可用多种方式例如jwt,此处不额外集成)
            String token = "Bearer " + username + "token";

            ConnectDTO connectDTO = ConnectDTO.builder()
            .name(username)
            .build();

            Object o = JSONObject.toJSONString(connectDTO);
            redisTemplate.opsForValue().set(token, o, globalConfig.getTimeNum(), globalConfig.timeUnit);


            loginResultDTO = LoginResultDTO.builder()
            .token(token)
            .build();
        }
    }

    return loginResultDTO;
}

最终效果-登录接口与数据接口

此时如果不登录,则会被拦截
image.png

此时需要先获取到token之后,在数据接口的访问中,增加一个令牌请求头参数Authorization
image.png
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544921.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ORA-00742 ORA-00312 恢复---惜分飞

有客户反馈,断电之后数据库启动报ORA-00742和ORA-00312,无法正常open 我们远程上去尝试open库结果也报同样错误 [oracleoldhis oradata]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Wed Apr 10 09:40:03 2024 Copyright (c) 1982, 2013, Oracle. A…

基于Springboot的汉服推广网站

基于SpringbootVue的汉服推广网站设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录页 首页 图文动态区 视频动态区 近期活动 汉服交流 汉服知识 后台登录页 后台首页…

基于SpringBoot的“汉服文化平台网站”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“汉服文化平台网站”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统功能界面图 用户登录、用…

海外代理IP是什么,如何使用?

海外代理IP是一种网络工具&#xff0c;它允许用户通过位于海外的服务器来访问互联网。这种技术的主要作用是帮助用户突破地域限制&#xff0c;解锁全球视野&#xff0c;并保护用户的隐私和安全。 具体来说&#xff0c;海外代理IP的工作原理是&#xff1a;用户的请求首先被发送…

2024年全球可穿戴腕带设备市场将增长 7%,蓝牙BLE助力其发展

根据市场调查机构 Canalys 今日发布的最新报告&#xff0c;2023 年&#xff0c;全球可穿戴腕带设备市场实现 1.4% 的温和增长&#xff0c;出货量达 1.85 亿台。该机构预测 2024 年&#xff0c;全球可穿戴腕带市场将增长 7%。 Canalys 对 2024 年可穿戴腕带市场持谨慎乐观的态…

每日一题---OJ题: 旋转数组

片头 嗨! 小伙伴们,咱们又见面啦,今天我们一起来学习一道OJ题---旋转数组 emmm,看上去好像没有那么难,我们一起来分析分析 比如: 数组里面有7个元素,分别为 1, 2, 3, 4, 5, 6, 7 , 现在我们将数组中的元素向右轮转3个位置 第一次轮转:将最后一个元素"7"放在第一个…

HashMap与HashSet的不安全问题

HashSet的不安全问题 HashSet与ArrayList一样也存在不安全的问题&#xff0c;当多线程时也会出现ConcurrentModificationException&#xff0c;并发修改异常需要提出解决方案 问题 public static void main(String[] args) {Set<Integer> set new HashSet<>();…

基于 Operator 部署 Prometheus 监控 k8s 集群

目录 一、环境准备 1.1 选择版本 1.2 过滤镜像 1.3 修改 yaml 镜像 1.4 移动 *networkPolicy*.yaml 1.5 修改 service 文件 1.6 提前下载镜像并推送到私有镜像仓库 1.7 修改镜像&#xff08;可选&#xff09; 二、执行创建 三、查看 pod 状态 四、访问 prometheus、…

计算机毕业设计springboot小区物业报修管理系统m8x57

该物业报修管理系统实施的目的在于帮助物业管理企业升级员工管理、住户管理、报修问题管理等内部管理平台&#xff0c;整合物业管理企业物力和人力&#xff0c;全面服务于维修人员管理的内部管理需求,并重视需求驱动、管理创新、与业主交流等外部需求,通过物业管理企业各项资源…

【深入理解Java IO流0x09】解读Java NIO核心知识(下篇)

1. NIO简介 在开始前&#xff0c;让我们再简单回顾一下NIO。 在传统的 Java I/O 模型&#xff08;BIO&#xff09;中&#xff0c;I/O 操作是以阻塞的方式进行的。也就是说&#xff0c;当一个线程执行一个 I/O 操作时&#xff0c;它会被阻塞直到操作完成。这种阻塞模型在处理多…

第⑫讲:Ceph集群OSD扩缩容中Reblanceing数据的重分布

文章目录 1.Reblanceing数据重分布的概念2.验证Reblanceing触发的过程3.Reblanceing细节4.临时关闭Reblanceing机制 1.Reblanceing数据重分布的概念 当集群中OSD进行扩缩容操作后&#xff0c;会触发一个Reblanceing数据重分布的机制&#xff0c;简单的理解就是将扩缩容前后OSD…

服务调用-微服务小白入门(4)

背景 各个服务应用&#xff0c;有很多restful api&#xff0c;不论是用哪种方式发布&#xff0c;部署&#xff0c;注册&#xff0c;发现&#xff0c;有很多场景需要各个微服务之间进行服务的调用&#xff0c;大多时候返回的json格式响应数据多&#xff0c;如果是前端直接调用倒…

AI python

AI python 软件方面程序上的人工智能&#xff0c;和物理那种能跑机器人没关系

超聚变服务器快速收集硬件故障日志方法(iBMC)

1、使用网线直接连接服务器的Mgmt口&#xff0c;另外一端连接电脑 2、电脑随便配置一个192.168.2.101段的IP&#xff0c;除100外 3、使用以下默认信息连接IBMC&#xff0c;即可成功登录 默认连接地址&#xff1a;192.168.2.100 默认账号&#xff1a;Administrator 默认密码&am…

【Vit】Vision Transformer 入门与理解

在学习VIT之前&#xff0c;建议先把 Transformer 搞明白了&#xff1a;【transformer】入门与理解 做了那些改进&#xff1f; 看图就比较明白了&#xff0c;VIT只用了Encoder的部分&#xff0c;把每一个图片裁剪成若干子图&#xff0c;然后把一个子图flatten一下&#xff0c;…

[大模型]Langchain-Chatchat安装和使用

项目地址&#xff1a; https://github.com/chatchat-space/Langchain-Chatchat 快速上手 1. 环境配置 首先&#xff0c;确保你的机器安装了 Python 3.8 - 3.11 (我们强烈推荐使用 Python3.11)。 $ python --version Python 3.11.7接着&#xff0c;创建一个虚拟环境&#xff…

力扣HOT100 - 240. 搜索二维矩阵 II

解题思路&#xff1a; 从左下角开始&#xff0c;根据条件删除行和列。 class Solution {public boolean searchMatrix(int[][] matrix, int target) {int row matrix.length - 1;int col matrix[0].length - 1;int l 0;while (row > 0 && l < col) {if (targ…

宝宝洗衣机怎么选?四款畅销卓越婴儿洗衣机深度剖析!

近几年科技高速发展&#xff0c;我们的生活也因此变得更加便捷、健康高效。尤其是在家庭生活中&#xff0c;各种新兴家电的出现让我们的生活变得更加健康卫生。婴儿洗衣机也为现代家庭提供了极大的便捷。由于婴儿刚出生免疫力比较弱&#xff0c;所以建议婴儿的衣物尽量和大人的…

【面试八股总结】排序算法(一)

参考资料 &#xff1a;阿秀 一、冒泡排序 冒泡排序就是把小的元素往前交换或者把大的元素往后交换&#xff0c;比较相邻的两个元素&#xff0c;交换也发生在这两个元素之间。具体步骤&#xff1a; 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。对每一对…

细胞活性和细胞增殖检测试剂盒--CCK8试剂盒

Cell Counting Kit-8又称CCK-8试剂盒或者CCK8试剂盒。CCK8试剂盒基于WST-8法检测细胞的细胞活性和细胞增殖。 WST-8是MTT的升级产品&#xff0c;试剂盒的工作原理是在电子耦合试剂存在的情况下&#xff0c;可以被线粒体内的脱氢酶还原生成高度 水溶性的橙黄色的甲臜产物&#…