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

JWT使用方法

目录

基础概念

依赖

生成令牌

工具类

控制层

解析令牌

工具类

网关过滤器

效果


基础概念

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案
为什么使用:

传统的intenet服务的认证是通过session进行的,当用户通过了安全认证后,则在服务端的session对象中保存该用户的认证信息,这样该用户对服务的访问被认为是安全的。这种模式的最大问题是没有分布式架构,不方便进行横向扩展,这种模式只适合于单体应用模式。如果需要进行服务集群则需要处理好共享session的问题。 如果一个庞大的系统需要按服务分解为多个独立的服务,使用分布式架构,则这种方式更难处理。使用jwt可以方便的处理上面提到的问题。
验证过程:

客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中,此后在于服务器的交互中都携带者JWT信息,它验证的方法其实很简单,只要把header做base64url解码,就能知道JWT用的什么算法做的签名,然后用这个算法,再次用同样的逻辑对header和payload做一次签名,并比较这个签名是否与JWT本身包含的第三个部分的串是否完全相同,只要不同,就可以认为这个JWT是一个被篡改过的串。

依赖

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><!--javax.xml.bind.DatatypeConverter java8 以后要加--><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency>

生成令牌

在登录过程中新建令牌,所以需要写在生产者中,并且根据数据库的用户和密码登录并判断其权限,根据给定的母版key、用户名、密码、权限生成其令牌。注意,这里设定了1小时候令牌过期。

工具类

@Component
public class JwtUtil {//加密 解密时的密钥 用来生成keypublic static final String JWT_KEY = "IT1995";/*** \* 生成加密后的秘钥 secretKey* <p>* \* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length,"AES");return key;}/*** \* 登录成功后生成token* \* @param id* \* @param account* \* @param role* \* @param ttlMillis* \* @return*/public static String createJWT(String id, Account account, String role, longttlMillis) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。long nowMillis = System.currentTimeMillis();//生成JWT的时间Date now = new Date(nowMillis);SecretKey key = generalKey();//生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。Map claims = new HashMap();claims.put("name", account.getUsername());claims.put("role", role);JwtBuilder builder = Jwts.builder()//这里其实就是new一个JwtBuilder,设置jwt的body.setClaims(claims) //如果有私有声明,一定要先设置这个自己创 建的私有的声明,这 个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声 明的 创建用户表.setId(id) //设置jti(JWT ID):是JWT的唯一标识,根 据业务需要,这个可以设置为 一个不重复的值,主要用来作为一次性token,从而回避重放攻击。.setIssuedAt(now) //iat: jwt的签发时间
// .setSubject(subject) //sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。.signWith(signatureAlgorithm, key);//设置签名使用的签名算法和签名使用的秘钥if (ttlMillis >= 0) {long expMillis = nowMillis + ttlMillis;Date exp = new Date(expMillis);builder.setExpiration(exp); //设置过期时间}return builder.compact(); //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt}/*** \* 密码解密对比方法4.编写mapper* 5.编写service根据用户名取的用户信息和权限* \* @param password* \* @param repassword* \* @return*/public static boolean matchsPassword(String password, String repassword) {BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();return encoder.matches(password, repassword);}
}

控制层

@RestController
public class LoginController {@AutowiredAccountService accountService;@RequestMapping("/login")public String Login(Account account) {String token = "没有token";//通过用户名拿到用户实体类Account result = accountService.loginByUserName(account.getUsername());if (result != null) {//然后进行密码的加密后的比较boolean b = JwtUtil.matchsPassword(account.getPassword(), result.getPassword());//如果密码一致表示登录成功if (result != null && b) {List<Authority> author = accountService.findAuthoritiesByUsername(account.getUsername());token = JwtUtil.createJWT(UUID.randomUUID().toString(), result, author.get(0).getAuthority(), 3600L * 1000);}}return token;}
}

解析令牌

给定令牌并解析,根据不同token,解析出对应的用户名、密码和权限,并判断访问内容,根据访问路径中的敏感词判断是否有权限查看页面。

工具类

@Component
public class JwtUtil {//加密 解密时的密钥 用来生成keypublic static final String JWT_KEY = "IT1995";/*** \* 生成加密后的秘钥 secretKey* <p>* \* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length,"AES");return key;}/*** \* 解析token* \* @param jwt* \* @return*/public static Claims parseJWT(String jwt) {SecretKey key = generalKey(); //签名秘钥,和生成的签名的秘钥一模一样Claims claims = Jwts.parser() //得到DefaultJwtParser.setSigningKey(key) //设置签名的秘钥.parseClaimsJws(jwt).getBody();//设置需要解析的jwtreturn claims;}
}

网关过滤器

@Component
public class gatewayConfig implements GlobalFilter, Ordered {private static final String AUTHORIZE_TOKEN = "token";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String requestPath = exchange.getRequest().getPath().value();// 1. 获取请求ServerHttpRequest request = exchange.getRequest();//2. 则获取响应ServerHttpResponse response = exchange.getResponse();//3. 如果是登录请求则放行if (request.getURI().getPath().contains("/login") || request.getURI().getPath().contains("/logout")) {return chain.filter(exchange);}//4. 获取请求头HttpHeaders headers = request.getHeaders();//5. 请求头中获取令牌String token = headers.getFirst(AUTHORIZE_TOKEN);//6. 判断请求头中是否有令牌if (StringUtils.isEmpty(token)) {//7. 响应中放入返回的状态吗, 没有权限访问response.setStatusCode(HttpStatus.UNAUTHORIZED);//8. 返回return response.setComplete();}//9. 如果请求头中有令牌则解析令牌try {Claims claims = JwtUtil.parseJWT(token);//获取token中的权限然后根据权限做访问权限String role = (String) claims.get("role");System.out.println(role);if (role.equals("vip")) {return chain.filter(exchange);}if (role.equals("common")) {if (request.getURI().getPath().contains("/vip")) {response.setStatusCode(HttpStatus.FORBIDDEN);//11. 返回return response.setComplete();}}} catch (Exception e) {e.printStackTrace();//10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现response.setStatusCode(HttpStatus.FORBIDDEN);//11. 返回return response.setComplete();}//12. 放行return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

效果

只有vip用户才能查看vip页面,普通用户查看vip页面403权限不足错误。如果没有登录令牌查看页面,401错误。

没有登录令牌

vip登录成功

普通用户访问vip 403

http://www.lryc.cn/news/352522.html

相关文章:

  • 使用鱼香肉丝一键安装重新安装ROS后mavros节点报错,.so文件不匹配
  • STM32+CubeMX移植SPI协议驱动W25Q16FLash存储器
  • gpt-4o考场安排
  • 【Unity AR开发插件】四、制作热更数据-AR图片识别场景
  • Spring AOP的实操 + 原理(动态代理)
  • 16.线性回归代码实现
  • Java进阶学习笔记1——课程介绍
  • 【全开源】沃德商协会管理系统源码(FastAdmin+ThinkPHP+Uniapp)
  • python毕设项目选题汇总(全)
  • c#从数据库读取数据到datagridview
  • 训练YOLOv9-S(注意:官方还没有提供YOLOv9-S的网络,我这是根据网络博客进行的步骤,按照0.33、0.50比例调整网络大小,参数量15.60M,计算量67.7GFLOPs)
  • 视觉检测实战项目——九点标定
  • android git提交代码命令以及常见命令的使用
  • 类图的六大关系
  • 家政项目day2 需求分析(模拟入职后熟悉业务流程)
  • 面试总结之:socket线路切换
  • 002 递归评论 mongodb websocket消息推送
  • 高开高走的续作,可不止《庆余年2》
  • uniapp android使用uni.chooseLocation,app云打包后,定位地址列表一直在加载中
  • 详解http协议
  • 台湾省军事演习路径规划:A*算法在复杂地形中的应用
  • OpenHarmony鸿蒙软总线使用mbedtls数据加密详解
  • 【JavaEE】Servlet
  • SpringBoot——整合Redis
  • 2024全新Langchain大模型AI应用与多智能体实战开发
  • 【JavaEE 初阶(十)】JVM
  • 【Flutter】AspectRatio组件Card组件按钮组件Wrap组件
  • 【IDEA软件应用篇】IDEA基础开发设置和开发快捷键
  • 机器学习--数学部分笔记
  • 基于springboot的在线宠物用品交易网站源码数据库