前言:

​ 之前使用过JWT TOKEN, 所生成的TOKEN过于繁琐, 且在用户维度操作上并不能满足业务需求.

JWT TOKEN自刷新,请点击此文章了解!

自定义TOKEN实现流程图:

需求:

1. Token过期时间为60分钟, 若用户正在持续操作则应该为token续期
2. 当用户登陆后,应该可以根据Token获取对应的用户,且在系统中用户只能在一个地方登陆
3. Token对应的权限应该可以进行统一鉴权

创建Token数据模型:

/* token 数据模型 */
public Token {//UUID => TOKEN => Redis KEYprivate String key;//用户信息 => Redis VALUEprivate User   user;// 创建token时间戳private Long   createTimestamp;// 当前token所对应的sessionId;private String sessionId;/* 省略 get set 方法 */
} /* 用户数据模型 */
public User {private String name;private String age;private String gender;// 权限路径列表private List<String> permissions;/* 省略 get set 方法 */
}

gateway拦截器:

/*** @author zly*/
@Slf4j
@Configuration
public class HttpRequestFilter implements GlobalFilter, Ordered {@Resourceprivate RedisService redisService;@Resourceprivate WhiteListProperties whiteListProperties;@Value("${spring.profiles.active}")private String env;private final static Long TIME_OUT = 1800000L;/*** 登录KEY前缀*/private static final String LOGIN_KEY = "LOGIN_KEY";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest serverHttpRequest = exchange.getRequest();String path = serverHttpRequest.getURI().getPath();String url = null;try {boolean res = false;String[] paths = path.split("/");if ("api".equals(paths[3])) {res = this.isCheckToken(path.split("api")[1]);} else {res = this.isCheckToken(paths[3]);}if (res) {url = path.split("api")[1];}} catch (Exception e) {// nothing}/* 参数校验 */this.checkParams(serverHttpRequest.getQueryParams());/* 权限校验 */if (StringUtils.isNotBlank(url)) {/* 校验请求token是否过期 */UserVO user = this.checkToken(serverHttpRequest);/* 白名单 */if (!whiteListProperties.getWhiteList().contains(url)) {/* 校验权限 */this.checkPermission(url, user.getPermissionUrls());}}return chain.filter(exchange);}private boolean isCheckToken(String path) {List<String> notCheckToken = whiteListProperties.getNotCheckToken();for (String url : notCheckToken) {if (url.contains(path)) {return false;}}return true;}private UserVO checkToken(ServerHttpRequest serverHttpRequest) {String token = serverHttpRequest.getHeaders().getFirst("token");ObjectMapper objectMapper = new ObjectMapper();Object key = redisService.getKey(LOGIN_KEY + token);if (Objects.isNull(key)) {throw new AuthException("登录超时,请重新登录!");}UserVO user = objectMapper.convertValue(key, UserVO.class);if (System.currentTimeMillis() - user.getTimestamp() > TIME_OUT) {/* 取出记录的时间戳与当前时间对比 若大于半小时则更新缓存,自动续期 */user.setTimestamp(System.currentTimeMillis());redisService.insert(LOGIN_KEY + token, user, 60, TimeUnit.MINUTES);}return user;}@Overridepublic int getOrder() {return 0;}/*** 参数校验** @param params 参数Map*/private void checkParams(MultiValueMap<String, String> params) {params.forEach((k, v) -> {String param = v.toString().toUpperCase();if (param.contains(ASTERISK) || param.contains(SINGLE_QUOTES)|| param.contains(WITH) || param.contains(QUESTION_MARK)|| param.contains(AND) || param.contains(SELECT)|| param.contains(OR) || param.contains(WHERE)|| param.contains(DROP) || param.contains(UPDATE)|| param.contains(SET) || param.contains(DELETE)|| param.contains(FROM) || param.contains(INSERT)|| param.contains(ILLEGAL_CHARACTER)) {throw new IllegalCharacterException("输入非法参数 : " + v.toString());}});}/*** 权限校验** @param url 访问路径*/private void checkPermission(String url, List<String> permissionUrls) {/* 开发环境省略权限校验 */if ("dev".equals(env)){return;}/* 权限路径匹配 */for (String permissionUrl : permissionUrls) {if (url.contains(permissionUrl)) {return;}}throw new ServiceException("权限不足!");}
}

异常拦截并统一返回:

/*** 覆盖默认的异常处理** @author yinjihuan*/
@Configuration
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorHandlerConfiguration {private final ServerProperties serverProperties;private final ApplicationContext applicationContext;private final ResourceProperties resourceProperties;private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public ErrorHandlerConfiguration(ServerProperties serverProperties,ResourceProperties resourceProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,ApplicationContext applicationContext) {this.serverProperties = serverProperties;this.applicationContext = applicationContext;this.resourceProperties = resourceProperties;this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,this.resourceProperties,this.serverProperties.getError(),this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());return exceptionHandler;}}

自定义用户认证异常:

/*** 自定义异常处理** <p>异常时用JSON代替HTML异常信息<p>** @author yinjihuan*/
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, resourceProperties, errorProperties, applicationContext);}/*** 获取异常属性*/@Overrideprotected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {int code = HttpStatus.INTERNAL_SERVER_ERROR.value();Throwable error = super.getError(request);/* 处理全局自定义异常类拦截 */if (error instanceof org.springframework.cloud.gateway.support.NotFoundException) {code = HttpStatus.NOT_FOUND.value();}if (error instanceof com.wisdom.pojo.exception.IllegalUrlException) {code = HttpStatus.BAD_REQUEST.value();}if (error instanceof com.wisdom.pojo.exception.IllegalCharacterException) {code = HttpStatus.NOT_ACCEPTABLE.value();}if (error instanceof com.wisdom.pojo.exception.AuthException) {code = HttpStatus.UNAUTHORIZED.value();}if (error instanceof com.wisdom.pojo.exception.ServiceException) {return response(HttpStatus.OK.value(), HttpStatus.BAD_REQUEST.value(), error.getMessage());}if (error instanceof org.springframework.web.server.ResponseStatusException) {code = HttpStatus.NOT_FOUND.value();}if (error instanceof com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException) {return response(HttpStatus.OK.value(), HttpStatus.SERVICE_UNAVAILABLE.value(),"访问频率过高,请稍后访问!");}if (error instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) {return response(HttpStatus.OK.value(), HttpStatus.SERVICE_UNAVAILABLE.value(),"访问频率过高,请稍后访问!");}return response(code, code, this.buildMessage(request, error));}/*** 指定响应处理方法为JSON处理的方法** @param errorAttributes 错误属性*/@Overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);}/*** 根据code获取对应的HttpStatus** @param errorAttributes 错误属性* @return httpStatus*/@Overrideprotected int getHttpStatus(Map<String, Object> errorAttributes) {int statusCode = (int) errorAttributes.get("http-code");HttpStatus httpStatus = HttpStatus.valueOf(statusCode);return httpStatus.value();}/*** 构建异常信息** @param request 请求域* @param ex      错误类* @return String*/private String buildMessage(ServerRequest request, Throwable ex) {StringBuilder message = new StringBuilder("Failed to handle request [");message.append(request.methodName());message.append(" ");message.append(request.uri());message.append("]");if (ex != null) {message.append(": ");message.append(ex.getMessage());}return message.toString();}/*** 构建返回的JSON数据格式** @param status       状态码* @param errorMessage 异常信息* @return Map*/public static Map<String, Object> response(int httpCode, int status, String errorMessage) {Map<String, Object> map = new HashMap<>(3);map.put("http-code", httpCode);map.put("code", status);map.put("message", errorMessage);map.put("data", null);return map;}}

源码地址:

在线自定义TOKEN源码地址

gateway权限统一认证相关推荐

  1. 微服务接入oauth2_微服务权限终极解决方案,Spring Cloud Gateway+Oauth2实现统一认证和鉴权!...

    最近发现了一个很好的微服务权限解决方案,可以通过认证服务进行统一认证,然后通过网关来统一校验认证和鉴权.此方案为目前最新方案,仅支持Spring Boot 2.2.0.Spring Cloud Hox ...

  2. SpringCloud Gateway 集成 oauth2 实现统一认证授权_03

    文章目录 一.网关搭建 1. 引入依赖 2. 配置文件 3. 增加权限管理器 4. 自定义认证接口管理类 5. 增加网关层的安全配置 6. 搭建授权认证中心 二.搭建产品服务 2.1. 创建boot项 ...

  3. 实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!

    今天这篇文章介绍一下Spring Cloud Gateway整合OAuth2.0实现认证授权,涉及到的知识点有点多,有不清楚的可以看下陈某的往期文章. 文章目录如下: 微服务认证方案 微服务认证方案目 ...

  4. 【Spring Cloud Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间这里只贴出关键部分代码的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证 ...

  5. 「springcloud 2021 系列」Spring Cloud Gateway + OAuth2 + JWT 实现统一认证与鉴权

    通过认证服务进行统一认证,然后通过网关来统一校验认证和鉴权. 将采用 Nacos 作为注册中心,Gateway 作为网关,使用 nimbus-jose-jwt JWT 库操作 JWT 令牌 理论介绍 ...

  6. SpringCloud系列教程(五)之SpringCloud Gateway 网关聚合开发文档 swagger knife4j 和登录权限统一验证【Hoxton版】

    阅读提醒: 本文面向的是有一定springboot基础者 本次教程使用的Spring Cloud Hoxton RELEASE版本 由于knife4j比swagger更加友好,所以本文集成knife4 ...

  7. 基于分布式微服务的SAAS统一认证平台

    ### ** 后台工程fintech介绍**客户端请求各个微服务服务的Api时,每个微服务都需要做相同的事情,比如认证.鉴权.限流.日志输出 单元测试等任务:通过spring cloud gatewa ...

  8. 【.NET Core项目实战-统一认证平台】开篇及目录索引

    [.NET Core项目实战-统一认证平台]开篇及目录索引 一.如何添加客户端授权? 在了解如何进行客户端授权时,我们需要了解详细的授权流程,在[.NET Core项目实战-统一认证平台]第八章 授权 ...

  9. 统一账号/统一认证系统的引入和搭建(LDAP)

    为什么需要统一账号/统一认证? 没人喜欢记忆一大堆混乱的账号和密码,员工不喜欢,企业更不喜欢. 企业要高效解决业务和研发问题,必须在初创期规划搭建必要的企业软件和研发工具,也就是进行IT基础设施中软件 ...

  10. 【.NET Core项目实战-统一认证平台】第四章 网关篇-数据库存储配置(2)

    [.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) 原文:[.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) [.NET Core项目实战- ...

最新文章

  1. 系统吞吐量(TPS)、用户并发量、性能测试概念和公式(转载)
  2. 19.7 主动模式和被动模式 添加监控主机 添加自定义模板 处理图形
  3. IOS多线程开发其实很简单
  4. 读书笔记_C#入门经典(第5版)第五章_变量的更多内容
  5. Bw树:新硬件平台的B树(内存数据库中的b树索引)
  6. php gd gif动画,我可以检测使用PHP和GD的animationGIF?
  7. 用Navicat_SSH 连接数据库服务器
  8. 互联网行业个人精进指南
  9. hello一直显示与服务器断开,新手问题--服务器环境部署hello world
  10. Qt4_使用QXmlStreamReader读取XML
  11. armbian ubuntu 桌面_Armbian国内源(Ubuntu18.04 Bionic)
  12. java 时间戳验证_关于Java:在时间戳服务器上使用时间戳和身份验证对jar进行签名...
  13. zzbird的bbsmax出了?
  14. 在哪里能找到各行业的分析研究报告?
  15. 大数据分析笔记 (2) - 数据分析统计方法
  16. 计算机无法识别出硬件,电脑检测不到硬盘,电脑硬件故障检测工具
  17. 数字人民币的基础:共识与信任
  18. 如何开启计算机的蓝牙功能吗,win7台式电脑蓝牙怎么开启(电脑蓝牙的开启步骤)...
  19. css背景图加载太慢怎么办,CSS实现background背景图优化,快速加载图片
  20. 免费软电话 — X-Lite 的安装及配置向导

热门文章

  1. MySQL OCP备考
  2. igm焊接机器人基本操作_焊接机器人技术讲解.ppt
  3. gaster字体转换器_gautami字体
  4. windows更新安装时出现此更新不适用于你的计算机的解决办法  dos 安装 msu
  5. 1、ESP8266入门(AT模式)——调试连接,使用USB-TTL
  6. 二分排序(java)
  7. 排序(二分插入排序)
  8. 2020 中国软件 100 强,腾讯第二、阿里第三,他第一!
  9. prn文件导入Matlab,PPP_code(Matlab) GPS精密单点定位中的周跳探测与修复的算法研究代码 GPS develop 238万源代码下载- www.pudn.com...
  10. chirp信号频谱(三角波和锯齿波)