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

ops/2024/11/20 19:39:09/

文章目录

    • 集成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: localhostport: 6379password: 123456timeout: 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;}@Overridepublic byte[] serialize(T t) throws SerializationException{if (t == null){return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic 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 {@Resourceprivate RedisTemplate<String,Object> redisTemplate;@Testvoid set(){redisTemplate.opsForValue().set("name123", "value123");}@Testvoid 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;@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Autowiredpublic void someComponent(GlobalConfig globalConfig) {this.globalConfig = globalConfig;}@Overridepublic 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);}@Overridepublic 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 {@Resourceprivate 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


http://www.ppmy.cn/ops/4338.html

相关文章

各自时间轴上

时间轴线交通阡陌上&#xff0c;相交相离间&#xff0c;成就时间流里的一份子&#xff0c;或大或小&#xff0c;皆在其内。哪有无缘无故&#xff0c;更没有突如其来&#xff0c;都是因缘际会&#xff0c;关键还是珍惜和把握。 ​顺水寻源&#xff0c;逐末求本&#xff0c;自然而…

C语言---贪吃蛇(二)---逻辑和代码的实现

文章目录 前言1.准备工作2.蛇的相关属性3.游戏流程设计3.1.游戏开始(GameStart)3.1.1.设置光标位置3.1.2.隐藏光标3.1.3.打印欢迎界面3.1.4.创建地图3.1.5.初始化蛇身3.1.6.创建食物 3.2.游戏运行(GameRun)3.2.1.打印信息栏3.2.2.蛇身的移动3.2.2.1.判断下一个结点是否为食物3.…

meta-llama/Meta-Llama-3-8B

https://huggingface.co/meta-llama/Meta-Llama-3-8B 型号细节 Meta开发并发布了Meta Llama 3家族大型语言模型(LLM),这是一组预训练和指令微调的生成性文本模型,大小为8B和70B参数。Llama 3指令微调模型针对对话用例进行了优化,在常见的行业基准测试中表现优于许多可用的开源…

centos7安装mysql5.7笔记

1 配置yum仓库 1.1更新密钥 #更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 1.2 下载使用wget命令下载MySQL的repo文件 #下载使用wget命令下载MySQL的repo文件 wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2 使用…

洛谷 P4779 [模板] 单源最短路径 题解 dijkstra算法

【模板】单源最短路径&#xff08;标准版&#xff09; 题目描述 给定一个 n n n 个点&#xff0c; m m m 条有向边的带非负权图&#xff0c;请你计算从 s s s 出发&#xff0c;到每个点的距离。 数据保证你能从 s s s 出发到任意点。 输入格式 第一行为三个正整数 n ,…

C语言Linux vim

1. actionmotion dG删到文件尾 ggdG先到开头再删除到末尾 d^到达行首 d$到行尾 2. num action 2dd删除两行 t"向后寻找"找到&#xff0c;找到前面一个位置 f"向后寻找"找到&#xff0c;直接找到本来的位置 diw删除单词并保持在视图状态&#xff…

Flask + Bootstrap vs Flask + React/Vue:初学者指南

好的&#xff0c;让我为你提供一个初学者指南&#xff0c;并附上一些示例代码来说明 Flask Bootstrap 和 Flask React/Vue 的使用。 Flask Bootstrap&#xff1a; 安装 Flask 和 Bootstrap&#xff1a; 首先&#xff0c;确保你已经安装了 Python 和 pip。然后可以使用 pip …

Ubuntu或Debian系统的漏洞修复:apt安装包管理工具

在阿里云主机管理后台->安全云中心&#xff0c;会看到系统最新的公布漏洞。 对于系统软件漏洞&#xff0c;我们还是要早做修复&#xff0c;防患于未然。 但安全云中心的功能大部分需要付费&#xff0c;包括一键修复&#xff0c;自己修复软件漏洞怎么操作呢&#xff1f; 其…