1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > SpringBoot(9)整合JWT实现Token验证

SpringBoot(9)整合JWT实现Token验证

时间:2023-03-18 06:47:13

相关推荐

SpringBoot(9)整合JWT实现Token验证

一、什么是JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC

7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

二、为什么要使用JWT

1.传统的session认证

http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。

session缺点

基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户

Session方式存储用户id的最大弊病在于要占用大量服务器内存,对于较大型应用而言可能还要保存许多的状态。

基于session认证暴露的问题

Session需要在服务器保存,暂用资源

扩展性 session认证保存在内存中 ,无法扩展到其他机器中

CSRF 基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

2.基于token的鉴权机制

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。除了用户id之外,还可以存储其他的和用户相关的信息,例如用户角色,用户性别等。

优点

简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。不需要在服务端保存会话信息,特别适用于分布式微服务。

三、JWT的结构

JWT是由三段信息构成的,将这三段信息文本用.连接一起就构成了JWT字符串。

就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

四、JWT的组成

JWT含有三个部分:

头部(header)载荷(payload)签证(signature)

1. 头部(header)

头部一般有两部分信息:类型、加密的算法(通常使用HMAC SHA256)

头部一般使用base64加密:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

解密后:

{"typ":"JWT","alg":"HS256"}

2. 载荷(payload)

该部分一般存放一些有效的信息。JWT的标准定义包含五个字段:

iss:该JWT的签发者sub:该JWT所面向的用户aud:接收该JWT的一方exp(expires):什么时候过期,这里是一个Unit的时间戳iat(issued at):在什么时候签发的

3. 签证(signature)

JWT最后一个部分。该部分是使用了HS256加密后的数据;包含三个部分:

header(base64后的)payload(base64后的)secret 私钥

secret是保存在服务器端的,JWT的签发生成也是在服务器端的,secret就是用来进行JWT的签发和JWT的验证,所以,它就是你服务端的秘钥,在任何场景都不应该流露出去。一旦客户端得知这个secret,那就意味着客户端可以自我签发JWT了。

五、JWT的使用

在身份鉴定的实现中,传统的方法是在服务端存储一个 session,给客户端返回一个 cookie,而使用JWT之后,当用户使用它的认证信息登录系统之后,会返回给用户一个JWT, 用户只需要本地保存该 token(通常使用localStorage,也可以使用cookie)即可。

当用户希望访问一个受保护的路由或者资源的时候,通常应该在 Authorization 头部使用 Bearer 模式添加JWT,其内容格式:

Authorization: Bearer <token>

因为用户的状态在服务端内容中是不存储的,所以这是一种无状态的认证机制。服务端的保护路由将会检查请求头 Authorization 中的JWT信息,如果合法,则允许用户的行为。由于JWT是 自包含的,因此,减少了需要查询数据库的需要。

JWT的这些特征使得我们可以完全依赖无状态的特性提供数据API服务。因为JWT并不使用Cookie的,所以你可以在任何域名提供你的API服务而不需要担心跨域资源共享问题(CORS)

六、流程

请求流程

用户使用账号和密码发出POST登录请求;服务器使用私钥创建一个JWT;服务器返回这个JWT给浏览器;浏览器将该JWT串放在请求头中向服务器发送请求;服务器验证该JWT;返回响应的资源给浏览器。

应用流程

初次登录生成JWT流程图

用户访问资源流程图

七、SpringBoot + JWT 实现

一、项目结构

R0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNjgxNzU1,size_16,color_FFFFFF,t_70)

二、pom.xml依赖

1. 引入JWT依赖

<!-- JWT token --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.2.0</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency>

2. 引入json jar包

<!-- json jar包--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.35</version></dependency>

3. 字符串工具类包

<dependency><groupId>mons</groupId><artifactId>commons-lang3</artifactId></dependency>

三、model包 创建配置信息的实体类、用户实体类

1. Audience 配置信息的实体类

import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.ponent;@Data@Componentpublic class Audience {//代表这个JWT的接收对象,存入audienceprivate String clientId = "098f6bcd4621d373cade4e832627b4f6";//密钥, 经过Base64加密, 可自行替换private String base64Secret = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=";//JWT的签发主体,存入issuerprivate String name = "restapiuser";//过期时间,时间戳private int expiresSecond = 172800;}

2. 用户实体类

import lombok.Data;@Datapublic class User {//主键private Integer id;//账户private String accountName;//密码private String password;//用户姓名private String userName;public User(Integer id,String accountName,String password,String userName){this.id = id;this.accountName = accountName;this.password = password;this.userName = userName;}public User(){}}

四、annotation包 创建注解类

1. JwtIgnore 注解

import java.lang.annotation.*;/*** ========================* JWT验证忽略注解* Created with IntelliJ IDEA.* Date:2002/6/5 9:50* Version: v1.0* ========================*/@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface JwtIgnore {}

五、common包 创建、自定义异常、返回结果、结果常量类

1. exception包 CustomException 自定义异常类

import com.mon.response.ResultCode;import java.text.MessageFormat;/*** 自定义异常类型* @author**/public class CustomException extends RuntimeException {//错误代码ResultCode resultCode;public CustomException(ResultCode resultCode){super(resultCode.message());this.resultCode = resultCode;}public CustomException(ResultCode resultCode, Object... args){super(resultCode.message());String message = MessageFormat.format(resultCode.message(), args);resultCode.setMessage(message);this.resultCode = resultCode;}public ResultCode getResultCode(){return resultCode;}}

2. response包 ResultCode 结果常量类

/*** ========================* 通用响应状态* Created with IntelliJ IDEA.* User:pyy* Date:/6/5* Time:10:10* Version: v1.0* ========================*/public enum ResultCode {/* 成功状态码 */SUCCESS(200,"操作成功!"),/* 错误状态码 */FAIL(-1,"操作失败!"),/* 参数错误:10001-19999 */PARAM_IS_INVALID(10001, "参数无效"),PARAM_IS_BLANK(10002, "参数为空"),PARAM_TYPE_BIND_ERROR(10003, "参数格式错误"),PARAM_NOT_COMPLETE(10004, "参数缺失"),/* 用户错误:20001-29999*/USER_NOT_LOGGED_IN(20001, "用户未登录,请先登录"),USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"),USER_NOT_EXIST(20004, "用户不存在"),USER_HAS_EXISTED(20005, "用户已存在"),/* 业务错误:30001-39999 */BUSINESS_GROUP_NO_ALLOWED_DEL(30001, "应用分组已经被应用使用,不能删除"),BUSINESS_THEME_NO_ALLOWED_DEL(30002, "主题已经被用户使用,不能删除"),BUSINESS_THEME_NO_ALLOWED_DISABLE(30003, "主题已经被用户使用,不能停用"),BUSINESS_THEME_DEFAULT_NO_ALLOWED_DEL(30004, "默认主题,不能删除"),BUSINESS_THEME_NO_ALLOWED_UPDATE(30005, "主题已经被用户使用,不能修改图片信息"),BUSINESS_IS_TOP(30040, "已经到最顶部"),BUSINESS_IS_BOTTOM(30041, "已经到最底部"),BUSINESS_NAME_EXISTED(30051, "名称已存在"),/* 系统错误:40001-49999 */SYSTEM_INNER_ERROR(40001, "系统繁忙,请稍后重试"),UPLOAD_ERROR(40002, "系统异常,上传文件失败"),FILE_MAX_SIZE_OVERFLOW(40003, "上传尺寸过大"),FILE_ACCEPT_NOT_SUPPORT(40004, "上传文件格式不支持"),SET_UP_AT_LEAST_ONE_ADMIN(40005, "至少指定一个管理员"),URL_INVALID(40006, "地址不合法"),LINK_AND_LOGOUT_NO_MATCH(40006, "主页地址和注销地址IP不一致"),IP_AND_PORT_EXISTED(40007, "当前IP和端口已经被占中"),LINK_IS_REQUIRED(40008, "生成第三方token认证信息: 主页地址不能为空,请完善信息"),ONLY_ROOT_DEPARTMENT(40009, "组织机构只能存在一个根机构"),DEPART_CODE_EXISTED(40010, "组织机构编码已存在"),DEPART_CONTAINS_USERS(40011, "该机构下是存在用户,不允许删除"),DEPART_CONTAINS_SON(40012, "该机构下是存在子级机构,不允许删除"),DEPART_PARENT_IS_SELF(40013, "选择的父机构不能为本身"),DICT_EXIST_DEPEND(40014, "该字典数据存在详情依赖,不允许删除"),DICT_DETAIL_LOCK(40015, "该字典数据被锁定,不允许修改或删除"),DEPART_CODE_EXISTED_WITH_ARGS(40016, "组织机构编码【{0}】系统已存在"),/* 数据错误:50001-599999 */RESULT_DATA_NONE(50001, "数据未找到"),DATA_IS_WRONG(50002, "数据有误"),DATA_ALREADY_EXISTED(50003, "数据已存在"),/* 接口错误:60001-69999 */INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"),INTERFACE_OUTTER_INVOKE_ERROR(60002, "外部系统接口调用异常"),INTERFACE_FORBID_VISIT(60003, "该接口禁止访问"),INTERFACE_ADDRESS_INVALID(60004, "接口地址无效"),INTERFACE_REQUEST_TIMEOUT(60005, "接口请求超时"),INTERFACE_EXCEED_LOAD(60006, "接口负载过高"),/* 权限错误:70001-79999 */PERMISSION_UNAUTHENTICATED(70001,"此操作需要登陆系统!"),PERMISSION_UNAUTHORISE(70002,"权限不足,无权操作!"),PERMISSION_EXPIRE(70003,"登录状态过期!"),PERMISSION_TOKEN_EXPIRED(70004, "token已过期"),PERMISSION_LIMIT(70005, "访问次数受限制"),PERMISSION_TOKEN_INVALID(70006, "无效token"),PERMISSION_SIGNATURE_ERROR(70007, "签名失败");//操作代码int code;//提示信息String message;ResultCode(int code, String message){this.code = code;this.message = message;}public int code() {return code;}public String message() {return message;}public void setCode(int code) {this.code = code;}public void setMessage(String message) {this.message = message;}}

3.response包 Result 返回结果类

import com.fasterxml.jackson.databind.annotation.JsonSerialize;/*** ========================* 统一响应结果集* Created with IntelliJ IDEA.* User:pyy* Date:/6/5* Time:10:10* Version: v1.0* ========================*/@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)public class Result<T> {//操作代码int code;//提示信息String message;//结果数据T data;public Result(ResultCode resultCode){this.code = resultCode.code();this.message = resultCode.message();}public Result(ResultCode resultCode, T data){this.code = resultCode.code();this.message = resultCode.message();this.data = data;}public Result(String message){this.message = message;}public static Result SUCCESS(){return new Result(ResultCode.SUCCESS);}public static <T> Result SUCCESS(T data){return new Result(ResultCode.SUCCESS, data);}public static Result FAIL(){return new Result(ResultCode.FAIL);}public static Result FAIL(String message){return new Result(message);}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}}

六、utils包 JWT工具类、加密工具类

1. Base64Util 加密工具类

import org.apache.tomcat.util.codec.binary.Base64;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.UnsupportedEncodingException;/*** ========================* Base64加密解密工具类* Created with IntelliJ IDEA.* Date:/6/5 9:25* Version: v1.0* ========================*/public class Base64Util {private static final Logger logger = LoggerFactory.getLogger(Base64Util.class);private static final String charset = "utf-8";/*** 解密* @param data* @return*/public static String decode(String data) {try {if (null == data) {return null;}return new String(Base64.decodeBase64(data.getBytes(charset)), charset);} catch (UnsupportedEncodingException e) {logger.error(String.format("字符串:%s,解密异常", data), e);}return null;}/*** 加密* @param data* @return*/public static String encode(String data) {try {if (null == data) {return null;}return new String(Base64.encodeBase64(data.getBytes(charset)), charset);} catch (UnsupportedEncodingException e) {logger.error(String.format("字符串:%s,加密异常", data), e);}return null;}}

2. JwtTokenUtil JWT工具类

import com.mon.exception.CustomException;import com.mon.response.ResultCode;import com.csdn.jwt.model.Audience;import com.csdn.jwt.model.User;import io.jsonwebtoken.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.crypto.spec.SecretKeySpec;import javax.xml.bind.DatatypeConverter;import java.security.Key;import java.util.Date;/*** ========================* Created with IntelliJ IDEA.* Date:/6/5 17:24* Version: v1.0* ========================*/public class JwtTokenUtil {private static Logger log = LoggerFactory.getLogger(JwtTokenUtil.class);public static final String AUTH_HEADER_KEY = "Authorization";public static final String TOKEN_PREFIX = "Bearer ";/*** 解析jwt* @param jsonWebToken* @param base64Security* @return*/public static Claims parseJWT(String jsonWebToken, String base64Security) {try {Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(base64Security)).parseClaimsJws(jsonWebToken).getBody();return claims;} catch (ExpiredJwtException eje) {log.error("===== Token过期 =====", eje);throw new CustomException(ResultCode.PERMISSION_TOKEN_EXPIRED);} catch (Exception e){log.error("===== token解析异常 =====", e);throw new CustomException(ResultCode.PERMISSION_TOKEN_INVALID);}}/*** 构建jwt* @param user* @param audience* @return*/public static String createJWT(User user, Audience audience) {try {// 使用HS256加密算法SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//生成JWT生效时间long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);//生成签名密钥byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(audience.getBase64Secret());Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());//添加构成JWT的参数JwtBuilder builder = Jwts.builder()//头部(header).setHeaderParam("typ", "JWT").setHeaderParam("alg",signatureAlgorithm.getValue())// 载荷(payload) 可以将基本不重要的对象信息放到claims.claim("accountName", user.getAccountName()).claim("id", user.getId())// 代表这个JWT的主体,即它的所有人.setSubject(user.getUserName())// 代表这个JWT的签发主体;.setIssuer(audience.getClientId())// 是一个时间戳,代表这个JWT的签发时间.setIssuedAt(new Date())// 代表这个JWT的接收对象.setAudience(audience.getName())//signatureAlgorithm:签名算法 signingKey:盐.signWith(signatureAlgorithm, signingKey);//添加Token过期时间int TTLMillis = audience.getExpiresSecond();if (TTLMillis >= 0) {long expMillis = nowMillis + TTLMillis;Date exp = new Date(expMillis);// 是一个时间戳,代表这个JWT的过期时间;builder.setExpiration(exp)// 是一个时间戳,代表这个JWT生效的开始时间,意味着在这个时间之前验证JWT是会失败的.setNotBefore(now);}//生成JWTreturn pact();} catch (Exception e) {log.error("签名失败", e);throw new CustomException(ResultCode.PERMISSION_SIGNATURE_ERROR);}}/*** 从token中获取用户名* @param token* @param base64Security* @return*/public static String getUsername(String token, String base64Security){return parseJWT(token, base64Security).getSubject();}/*** 从token中获取用户ID* @param token* @param base64Security* @return*/public static Integer getUserId(String token, String base64Security){Integer userId = parseJWT(token, base64Security).get("id",Integer.class);return userId;}/*** 从token中获取用户账户* @param token* @param base64Security* @return*/public static String getAccountName(String token, String base64Security){String accountName = parseJWT(token, base64Security).get("accountName",String.class);return accountName;}/*** 是否已过期* @param token* @param base64Security* @return*/public static boolean isExpiration(String token, String base64Security) {return parseJWT(token, base64Security).getExpiration().before(new Date());}public static void main(String[] args){Audience audience = new Audience();User user = new User(101,"admin","admin123","张三");String token = createJWT(user,audience);// System.out.println(token);Integer id = getUserId(token,audience.getBase64Secret());System.out.println(getAccountName(token,audience.getBase64Secret()));}}

七、config包 配置异常处理器、拦截器

1. CustomExceptionConfig 异常处理器

import com.mon.exception.CustomException;import com.mon.response.Result;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseStatus;import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.servlet.http.HttpServletRequest;@RestControllerAdvicepublic class CustomExceptionConfig {@ResponseStatus(HttpStatus.OK)@ExceptionHandler(CustomException.class)public Result handleMissingServletRequestParameterException(HttpServletRequest request, CustomException e) {Result result = new Result(e.getResultCode());return result;}}

2. JwtInterceptor 创建JWT验证拦截器

import com.csdn.jwt.annotation.JwtIgnore;import com.mon.exception.CustomException;import com.mon.response.ResultCode;import com.csdn.jwt.model.Audience;import com.csdn.jwt.utils.JwtTokenUtil;import lombok.extern.slf4j.Slf4j;import mons.lang3.StringUtils;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpMethod;import org.springframework.web.context.support.WebApplicationContextUtils;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** ========================* token验证拦截器* Created with IntelliJ IDEA.* Date:/6/5 9:46* Version: v1.0* ========================*/@Slf4jpublic class JwtInterceptor extends HandlerInterceptorAdapter{@Autowiredprivate Audience audience;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 忽略带JwtIgnore注解的请求, 不做后续token认证校验if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;JwtIgnore jwtIgnore = handlerMethod.getMethodAnnotation(JwtIgnore.class);if (jwtIgnore != null) {return true;}}if (HttpMethod.OPTIONS.equals(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return true;}// 获取请求头信息authorization信息final String authHeader = request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);log.info("## authHeader= {}", authHeader);if (StringUtils.isBlank(authHeader) || !authHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) {log.info("### 用户未登录,请先登录 ###");throw new CustomException(ResultCode.USER_NOT_LOGGED_IN);}// 获取tokenfinal String token = authHeader.substring(7);if(audience == null){BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());audience = (Audience) factory.getBean("audience");}// 验证token是否有效--无效已做异常抛出,由全局异常处理后返回对应信息JwtTokenUtil.parseJWT(token, audience.getBase64Secret());return true;}}

3. CustomWebMvcConfigurer 配置主拦截器

import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.InterceptorRegistration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;//主拦截器,根据拦截不同路径跳转不同自定义拦截器 (实现WebMvcConfigurer方法)@Configurationpublic class CustomWebMvcConfigurer implements WebMvcConfigurer {/*** 添加拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {//拦截路径可自行配置多个 可用 ,分隔开InterceptorRegistration addInterceptor = registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**");//排除拦截路径//addInterceptor.excludePathPatterns("/user/login");//addInterceptor.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");//拦截配置addInterceptor.addPathPatterns("/**");}/*** 跨域支持** @param registry*/@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD").maxAge(3600 * 24);}}

八、编写测试Controller接口

1. UserController 创建controller类

import com.alibaba.fastjson.JSONObject;import com.csdn.jwt.annotation.JwtIgnore;import com.mon.response.Result;import com.csdn.jwt.model.Audience;import com.csdn.jwt.model.User;import com.csdn.jwt.utils.JwtTokenUtil;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;@CrossOrigin@RequestMapping("/user")@RestController@Slf4jpublic class UserController {@Autowiredprivate Audience audience;@PostMapping("/login")@JwtIgnorepublic Result adminLogin(HttpServletResponse response, String userName, String password) {// 这里模拟测试, 默认登录成功,返回User对象User user = new User(101,"admin","admin123","张三");// 创建tokenString token = JwtTokenUtil.createJWT(user,audience);log.info("### 登录成功, token={} ###", token);// 将token放在响应头response.setHeader(JwtTokenUtil.AUTH_HEADER_KEY, JwtTokenUtil.TOKEN_PREFIX + token);// 将token响应给客户端JSONObject result = new JSONObject();result.put("token", token);return Result.SUCCESS(result);}@GetMapping("/users")public Result userList() {log.info("### 查询所有用户列表 ###");return Result.SUCCESS();}}

九、接下来我们使用PostMan工具进行测试

先登陆:

携带生成token再次访问:http://localhost:8080/user/users 接口

这里选择 Bearer Token类型,就把不要在 Token中手动Bearer,postman会自动拼接。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。