免费申请做网站平台,上海微信网站,临沂 网站推广,大型移动网站开发文章目录 前言一、JWT1. 什么是JWT2. 使用场景3. 结构3.1 Header3.2 Payload3.3 Signature 4. 使用 二、案例1.引入库2.JwtUtils3. UserController14. ArticleController 三、拦截器1. 定义拦截器2. 注册拦截器 四、测试1. 登录2. 无token3. 有token4. 全局配置 总结 前言
前面… 文章目录 前言一、JWT1. 什么是JWT2. 使用场景3. 结构3.1 Header3.2 Payload3.3 Signature 4. 使用 二、案例1.引入库2.JwtUtils3. UserController14. ArticleController 三、拦截器1. 定义拦截器2. 注册拦截器 四、测试1. 登录2. 无token3. 有token4. 全局配置 总结 前言
前面已经完成了用户注册这里我们基于之前的用户表完成用户的登录接口。 一、JWT
1. 什么是JWT
JWT全称JSON Web TokenJSON Web令牌JWT是一种开放标准RFC 7519它定义了一种紧凑且自包含的方式用于作为JSON对象在各方之间安全地传输信息。此信息是经过数字签名的因此可以验证和信任。JWT可以使用秘密使用HMAC算法或使用RSA或ECDSA的公钥/私钥对进行签名。
虽然JWT可以加密也可以在各方之间提供保密性但我们将专注于签名代币。签名令牌可以验证其中包含的声明的完整性而加密令牌则向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时签名还证明只有持有私钥的一方才是签名方。
2. 使用场景
以下是JSON Web令牌有用的一些场景
授权这是使用JWT最常见的场景。一旦用户登录每个后续请求都将包括JWT允许用户访问该令牌允许的路由、服务和资源。单点登录是目前广泛使用JWT的一个功能因为它的开销很小并且能够在不同的域中轻松使用。
信息交换JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名——例如使用公钥/私钥对——所以你可以确保发送者就是他们所说的那个人。此外由于签名是使用标头和有效载荷计算的因此还可以验证内容是否未被篡改。
3. 结构 以.作为各部分分隔符 xxxxx.yyyyy.zzzzz HeaderPayloadSignature
3.1 Header 算法可以使用 HMAC SHA256 or RSA {alg: HS256,typ: JWT
}java-jwt 支持以下签名和验证算法
JWSAlgorithmDescriptionHS256HMAC256HMAC with SHA-256HS384HMAC384HMAC with SHA-384HS512HMAC512HMAC with SHA-512RS256RSA256RSASSA-PKCS1-v1_5 with SHA-256RS384RSA384RSASSA-PKCS1-v1_5 with SHA-384RS512RSA512RSASSA-PKCS1-v1_5 with SHA-512ES256ECDSA256ECDSA with curve P-256 and SHA-256ES384ECDSA384ECDSA with curve P-384 and SHA-384ES512ECDSA512ECDSA with curve P-521 and SHA-512
3.2 Payload 有效载荷用来存放一些用户信息但不建议存放用户私密信息以免造成不必要的安全隐患。 {sub: 1234567890,name: John Doe,admin: true
}3.3 Signature 签名用于验证消息在发送过程中没有更改并且在使用私钥签名的令牌的情况下它还可以验证JWT的发送者是它所说的那个人。 HMACSHA256(base64UrlEncode(header) . base64UrlEncode(payload),secret)4. 使用 在身份验证中当用户使用其凭据成功登录时将返回一个JSON Web令牌。由于令牌是凭据因此必须非常小心地防止出现安全问题。一般来说您不应将令牌保存的时间超过所需的时间。 每当用户想要访问受保护的路由或资源时用户代理都应该发送JWT通常在Authorization头中使用Bearer模式。标头的内容应如下所示 Authorization: Bearer token请注意如果您通过HTTP头发送JWT令牌则应尽量防止它们变大。有些服务器不接受超过8 KB的标头。如果您试图在JWT令牌中嵌入太多信息例如通过包括所有用户的权限您可能需要一个替代解决方案如Auth0细粒度授权。 如果令牌是在Authorization标头中发送的则跨来源资源共享CORS不会成为问题因为它不使用cookie。
下图显示了如何获取JWT并将其用于访问API或资源
二、案例
1.引入库
dependencygroupIdcom.auth0/groupIdartifactIdjava-jwt/artifactIdversion4.4.0/version
/dependency2.JwtUtils
package org.example.springboot3.bigevent.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.Map;public class JwtUtils {private static final String SECRET 167589447321;/*** 生成token* param claims 用户信息* return String*/public static String create(MapString, Object claims) {return JWT.create().withClaim(claims, claims).withIssuer(auth0).withExpiresAt(new Date(System.currentTimeMillis() 1000 * 60 * 60 * 24)).sign(Algorithm.HMAC256(SECRET));}/*** 验证token* param token token* return boolean*/public static boolean verify(String token) {DecodedJWT decodedJWT;try {Algorithm algorithm Algorithm.HMAC256(SECRET);JWTVerifier verifier JWT.require(algorithm)// specify any specific claim validations.withIssuer(auth0)// reusable verifier instance.build();decodedJWT verifier.verify(token);} catch (JWTVerificationException exception){// Invalid signature/claimsreturn false;}return true;}/*** 解析token数据* param token token* return Map*/public static MapString, Object getClaims(String token) {return JWT.require(Algorithm.HMAC256(SECRET)).withIssuer(auth0).build().verify(token).getClaim(claims).asMap();}}
3. UserController1
package org.example.springboot3.bigevent.controller;import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import org.example.springboot3.bigevent.entity.Result;
import org.example.springboot3.bigevent.entity.User;
import org.example.springboot3.bigevent.service.UserSerivce;
import org.example.springboot3.bigevent.utils.JwtUtils;
import org.example.springboot3.bigevent.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;/*** Create by zjg on 2024/5/22*/
RequestMapping(/user/)
RestController
Validated
public class UserController1 {AutowiredUserSerivce userSerivce;RequestMapping(register)public Result register(Pattern(regexp ^\\S{6,20}$,message 用户名长度为6-20位) String username,Pattern(regexp ^\\S{8,20}$,message 密码为8-20位) String password){User useruserSerivce.findUserByName(username);if(usernull){//用户不存在,可以注册int iuserSerivce.addUser(username,password);if(i!1){return Result.error(失败注册,请稍后重新注册!);}}else{return Result.error(该用户已存在,请重新注册!);}return Result.success();}RequestMapping(register1)public Result register1(Valid User user){if(userSerivce.findUserByName(user.getUsername())null){//用户不存在,可以注册int iuserSerivce.addUser(user.getUsername(),user.getPassword());if(i!1){return Result.error(失败注册,请稍后重新注册!);}}else{return Result.error(该用户已存在,请重新注册!);}return Result.success();}RequestMapping(login)public Result login(Valid User loginUser){String message用户名/密码不正确;User user userSerivce.findUserByName(loginUser.getUsername());if(user!null){//用户存在if(user.getPassword().equals(Md5Util.getMD5String(loginUser.getPassword()))){//密码正确MapString,Object claimsnew HashMap();claims.put(userId,user.getId());claims.put(username,user.getUsername());String token JwtUtils.create(claims);return Result.success(登录成功,token);}}return Result.error(message);}//todo 登出暂未使用RequestMapping(logout)public Result logout(Valid User loginUser){String message用户名/密码不正确;User user userSerivce.findUserByName(loginUser.getUsername());if(user!null){//用户存在if(user.getPassword().equals(Md5Util.getMD5String(loginUser.getPassword()))){//密码正确MapString,Object claimsnew HashMap();claims.put(userId,user.getId());claims.put(userUsername,user.getUsername());String token JwtUtils.create(claims);return Result.success(token);}}return Result.error(message);}
}
4. ArticleController 主要为测试使用 package org.example.springboot3.bigevent.controller;import org.example.springboot3.bigevent.entity.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Create by zjg on 2024/5/26*/
RestController
RequestMapping(/article/)
public class ArticleController {RequestMapping(list)public ResultString list(){return Result.success(article.list);}
}
三、拦截器
1. 定义拦截器 我们使用拦截器来对接口进行横切面的token验证 package org.example.springboot3.bigevent.inceptors;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.springboot3.bigevent.entity.Result;
import org.example.springboot3.bigevent.utils.JwtUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;/*** Create by zjg on 2024/5/26*/
Component
public class LoginInceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token request.getHeader(Authorization);if(token!nulltoken.contains(Bearer)){boolean verify JwtUtils.verify(token.substring(token.indexOf(Bearer)7));if(verify){return true;}}response.setStatus(HttpStatus.UNAUTHORIZED.value());response.setContentType(application/json;charsetUTF-8);ObjectMapper objectMapper new ObjectMapper();objectMapper.writerFor(Result.class);String message objectMapper.writeValueAsString(Result.error(token验证失败,请重新获取token后重试!));response.getWriter().println(message);return false;}
}
2. 注册拦截器 拦截器拦截初注册和登录之外的所有请求 package org.example.springboot3.config;import org.example.springboot3.bigevent.inceptors.LoginInceptor;
import org.springframework.beans.factory.annotation.Autowired;
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;/*** Create by zjg on 2024/5/26*/
Configuration
public class WebMvcConfig implements WebMvcConfigurer {AutowiredLoginInceptor loginInceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {ListString patternsnew ArrayList();patterns.add(/user/register);patterns.add(/user/login);registry.addInterceptor(loginInceptor).excludePathPatterns(patterns);}
}
四、测试
1. 登录 2. 无token 3. 有token 4. 全局配置 在Postman中可以对目录配置token认证信息对目录下的全部接口生效。 总结
回到顶部 JWT官网 JWT快速入门