springboot项目jwt认证鉴权(企业级实现方案)

说明

背景:项目采用springcloud框架,用户鉴权从网关走的,但是当单独部署springboot服务时,没有鉴权第三方扫描通不过。

方案:在springboot微服务中单独集成jwt鉴权。

一、引入依赖

		<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency>

二、自定义拦截器

package com.gstanzer.supervise.jwt;import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.gstanzer.supervise.common.CommonData;
import com.gstanzer.supervise.exception.TokenException;
import com.gstanzer.supervise.redis.CtgRedisUtil;
import com.gstanzer.supervise.utills.RedisUtils;
import com.gstanzer.supervise.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;public class AuthenticationInterceptor implements HandlerInterceptor {private static Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);@Resourceprivate CtgRedisUtil redisUtils;//    @Resource
//    private RedisUtils redisUtils;@Value(("${token.expire.time}"))private Integer expireTime;@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {// 从 http 请求头中取出 tokenString token = httpServletRequest.getHeader("gst-token");// 如果不是映射到方法直接通过if(!(object instanceof HandlerMethod)){return true;}HandlerMethod handlerMethod=(HandlerMethod)object;Method method=handlerMethod.getMethod();//检查是否有passtoken注释,有则跳过认证if (method.isAnnotationPresent(PassToken.class)) {PassToken passToken = method.getAnnotation(PassToken.class);if (passToken.required()) {logger.info("=====pass token 跳过token 拦截=====");return true;}}// 执行认证if (token == null) {logger.info("token:" + token);logger.info("请求路径:" + httpServletRequest.getRequestURI());throw new TokenException("无token,请重新登录","tokenError");}// 解析token信息String userId = "";Map<String, String> userMap = TokenUtils.getUserInfoByToken(token);if (userMap != null) {userId = userMap.get("userId");logger.info("解析token获得userId为:{}", userId);}if(redisUtils.exists("token_"+userId)){//更新token有效时间redisUtils.set("token_"+userId, token, expireTime);
//            redisUtils.set("token_"+userId, token, Long.valueOf(String.valueOf(expireTime)), TimeUnit.SECONDS);}else{throw new TokenException("token过期或失效,请重新登录","tokenError");}// 验证 tokenverifyToken(token);logger.info("请求的URL==>"+httpServletRequest.getRequestURI());return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}public static JSONObject verifyToken(String token) {DecodedJWT jwt = null;JSONObject resultMap = new JSONObject();resultMap.put("tokenExpires", false);resultMap.put("illegalToken", false);try {JWTVerifier verifier = JWT.require(Algorithm.HMAC256(CommonData.SECRET)).build();jwt = verifier.verify(token);//失效时间Date expiresDate = jwt.getExpiresAt();//token生成时间Date issuedDate = jwt.getIssuedAt();jwt.getIssuer();//头信息Map<String, Claim> map = jwt.getClaims();resultMap.put("head", map);resultMap.put("expiresDate", expiresDate);resultMap.put("issuedDate", issuedDate);} catch(JWTDecodeException e){resultMap.put("illegalToken", true);logger.error("token校验异常,token非法"+e.getMessage());throw new TokenException("token校验异常,token非法","tokenError");} catch (TokenExpiredException e) {resultMap.put("tokenExpires", true);logger.error("token校验异常,'{}'已经失效'{}'",token,e.getMessage());throw new TokenException("token过期或失效,请重新登录","tokenError");}return resultMap;}
}

三、实现WebMvcConfigurer将拦截器加入WebMvc配置

package com.gstanzer.supervise.jwt;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.ArrayList;
import java.util.List;/*** 新建Token拦截器*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {List<String> excludeUrl = new ArrayList<String>();excludeUrl.add("/swagger-ui/index.html");excludeUrl.add("/swagger-resources/**");excludeUrl.add("*/csrf");excludeUrl.add("/error");excludeUrl.add("**/api-docs");excludeUrl.add("**/v2/api-docs");excludeUrl.add("/v2/api-docs");excludeUrl.add("/bw-clnt-supervise-service/v2/api-docs");excludeUrl.add("/v2/consumerDevice/**");excludeUrl.add("/v2/vatToken/**");excludeUrl.add("/api/**");excludeUrl.add("/webjars/springfox-swagger-ui/**");registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**").excludePathPatterns(excludeUrl);    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录}@Beanpublic AuthenticationInterceptor authenticationInterceptor() {return new AuthenticationInterceptor();// 自己写的拦截器}}

四、新增token放行注解

package com.gstanzer.supervise.jwt;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {boolean required() default true;
}

五、需要放行的接口上加@PassToken注解即可放行

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLM - 大语言模型的自注意力(Self-Attention)机制基础 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136623432 注意力(Attention)机制是大型语言模型中的一个重要组成部分&#xff0c;帮助模型决定在处理信息时&#xff0c;所应该关注的部…

52、WEB攻防——通用漏洞弱口令安全服务协议web应用

文章目录 web类——加密&验证码后台服务类——SSH&RDP远程终端猜解应用类——zip&word文件压缩猜解 弱口令没有严格的定义&#xff0c;通常认为容易被别人猜测到或被破解工具破解的口令均为弱口令&#xff0c;通常与管理的安全意识和平台的初始化配置等相关&#x…

LeetCode.2864. 最大二进制奇数

题目 2864. 最大二进制奇数 分析 这道题目其实我们只需要保证最后一位是1&#xff0c;其余的1都放在最前面&#xff0c;这样得到的就是最大二进制奇数。 所以&#xff0c;我们先统计给定的字符串有多少个 1&#xff0c;多少个 0&#xff0c;把其中一个 1 放在最后一位&…

LORA_ LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

paper: https://arxiv.org/pdf/2106.09685.pdf code: https://github.com/microsoft/LoRA 摘要 作者提出了低秩自适应&#xff0c;或称LoRA&#xff0c;它冻结了预先训练的模型权值&#xff0c;并将可训练的秩分解矩阵注入变压器架构的每一层&#xff0c;大大减少了下游任务的…

alibaba druid 数据库连接池入门介绍

Apache druid Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。 快速开始 maven <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.15</version> </depend…

python实现websocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它允许客户端和服务器之间进行实时数据传输&#xff0c;而不是像 HTTP 协议那样&#xff0c;每次请求都需要建立新的连接。WebSocket 协议最初是由 HTML5 定义的&#xff0c;旨在提供一种更有效的替代方案&#xff0c;…

Python爬虫实战入门:豆瓣电影Top250(保你会,不会来打我)

文章目录 需求所需第三方库requests模块lxml模块了解 lxml模块和xpath语法xpath语法-基础节点选择语法 实战教程完整代码 需求 目标网站: https://movie.douban.com/top250 需求: 爬取电影中文名、英文名、电影详情页链接、导演、主演、上映年份、国籍、类型、评分、评分人数, …

AIGC笔记--关节点6D位姿按比例融合

1--核心代码 6D位姿一般指平移向量和旋转向量&#xff0c;Maya软件中关节点的6D位姿指的是相对平移向量和欧拉旋转向量&#xff1b; 为了按比例融合两个Pose&#xff0c;首先需要将欧拉旋转向量转换为旋转矩阵&#xff0c;在将旋转矩阵转换为四元数&#xff0c;利用球面线性插值…

springboot项目自定义切面增强方法功能(springboot记录日志)

说明 背景&#xff1a;记录系统接口日志入库&#xff0c;包含接口方法、入参、回参、响应时间、操作人、操作时间等信息。 方案&#xff1a;添加自定义切面处理 一、自定义切面注解 package com.gstanzer.supervise.annotation;import com.gstanzer.supervise.enums.Busine…

中宣部防沉迷系统PHP版本(管局防沉迷验证-PHP-全版本-接口测试样例)

现在对接游戏&#xff0c;无论是登录还是支付都是要去对接防沉迷实名认证接口&#xff0c;但前期的话你要登录网络游戏防沉迷实名认证系统进行接口测试&#xff0c;$appid &#xff0c;$bizId&#xff0c;$key去接口测试页面找&#xff08;正式上线在密钥管理&#xff09;&…

【LeetCode每日一题】2864. 最大二进制奇数

一.题目要求 给你一个 二进制 字符串 s &#xff0c;其中至少包含一个 ‘1’ 。 你必须按某种方式 重新排列 字符串中的位&#xff0c;使得到的二进制数字是可以由该组合生成的 最大二进制奇数 。 以字符串形式&#xff0c;表示并返回可以由给定组合生成的最大二进制奇数。 注…

基于jsp+mysql+Spring+mybatis的SSM汽车保险理赔管理系统设计和实现

基于jspmysqlSpringmybatis的SSM汽车保险理赔管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐…

vue3速查笔记

文章目录 一、创建Vue3.0工程1.使用 vue-cli 创建2.使用 vite 创建 二、常用 Composition API1.拉开序幕的setup2.ref函数3.reactive函数4.Vue3.0中的响应式原理vue2.x的响应式Vue3.0的响应式 5.reactive对比ref6.setup的两个注意点7.计算属性与监视1.computed函数2.watch函数3…

find_package 总结

本文参考&#xff1a;“轻松搞定CMake”系列之find_package用法详解 原理 find_package 即在指定目录CMAKE_MODULE_PATH 或 CMAKE_PREFIX_PATH查找对应的cmake文件。 find 模式 Module模式(默认)&#xff1a;查询Findxxx.cmake配置文件, 在CMAKE_MODULE_PATH 目录Config模式…

UGUI Text 重写Spacing字体间距

using UnityEngine; using UnityEngine.UI;[AddComponentMenu("UI/Effect/UGUITextSpacing")] [RequireComponent(typeof(UnityEngine.UI.Text))]//Text组件是必须的 public class UGUITextSpacing : BaseMeshEffect {public enum HorizontalAligmentType{Left,Cente…

Linux系统运维脚本:如何检测出Linux的僵尸进程、并清除僵尸进程

目 录 一、僵尸进程的定义及其危害 1、僵尸进程的定义 2、僵尸进程的危害 二、如何检测linux的僵尸进程 1、使用Top命令&#xff1a; 2、使用ps命令&#xff1a; 三、如何清除linux的僵尸进程 1. 确保父进程正确回收子进程 2. 重启父进程 3. 使用ini…

Mysql数据库“消失”的对象校验

文章目录 一、前言二、问题三、问题排查四、解决方式1.存储过程和函数的definer&#xff1a;2.修改event的definer:3.修改view的definer&#xff1a; 五、结束语 一、前言 最近在配合系统开发商进行上线的过程中&#xff0c;遇到了一个问题&#xff0c;从这个问题上&#xff0…

[SaaS] 家作->装修设计师

淘宝设计AI&#xff0c;人人都能成为装修设计师构建用户对未来家的想象&#xff0c;是家装家居多年来持续探索的方向&#xff0c;如今我们用AI帮助用户“更快、更好、更简单”看到自己未来的家。https://mp.weixin.qq.com/s/Pk1xztEd17JefXp79FHKNA其实就是个商品白底图inpaint…

SQLiteC/C++接口详细介绍-sqlite3类(一)

快速跳转文章列表&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口简介 下一篇&#xff1a;SQLiteC/C接口详细介绍&#xff08;二&#xff09; 引言&#xff1a; SQLite C/C 数据库接口是一个流行的SQLite库使用形式&#xff0c;它允许开发者在C和C代码中嵌…

WPF布局、控件与样式

视频来源&#xff1a;https://www.bilibili.com/video/BV1HC4y1b76v/ 布局 常用布局属性 HorizontalAlignment&#xff1a;用于设置元素的水平位置VerticalAlignment&#xff1a;用于设置元素的垂直位置Margin&#xff1a;指定元素与容器的边距Height&#xff1a;指定元素的…