当前位置:网站首页>JWT登录验证
JWT登录验证
2022-06-29 17:59:00 【不爱健身的数学子弟不是好程序员】

目录
一、JWT是什么?
1.概念
JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。是由用户以用户名、密码登录,服务端验证后,会生成一个 token,返回给客户端,客户端在下次访问的过程中携带这个 token,服务端责每次验证这个token。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。
2.结构
- 标头(Header)
- 有效载荷(Payload)
- 签名(Signature)
二、书写工具(config)包
在SpringBoot项目下创建config(工具包)包,在包底下创建一下类和枚举。
1.JwtUtils
package com.alanx.java.util;
import com.alanx.java.bean.Users;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
public class JwtUtils {
//常量
public static final long EXPIRE = 1000 * 60 * 60 * 24; //token过期时间
public static final String APP_SECRET = "13579"; //秘钥,加盐
// @param id 当前用户ID
// @param issuer 该JWT的签发者,是否使用是可选的
// @param subject 该JWT所面向的用户,是否使用是可选的
// @param ttlMillis 什么时候过期,这里是一个Unix时间戳,是否使用是可选的
// @param audience 接收该JWT的一方,是否使用是可选的
//生成token字符串的方法
public static String getJwtToken(Users user) {
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT") //头部信息
.setHeaderParam("alg", "HS256") //头部信息
//下面这部分是payload部分
// 设置默认标签
.setSubject("alanx") //设置jwt所面向的用户
.setIssuedAt(new Date()) //设置签证生效的时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) //设置签证失效的时间
//自定义的信息,这里存储id和姓名信息
.claim("id", user.getId()) //设置token主体部分 ,存储用户信息
.claim("name", user.getUserName())
.claim("nickName",user.getNickName())
//下面是第三部分
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
// 生成的字符串就是jwt信息,这个通常要返回出去
return JwtToken;
}
/**
* 判断token是否存在与有效
* 直接判断字符串形式的jwt字符串
*
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if (StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* 因为通常jwt都是在请求头中携带,此方法传入的参数是请求
*
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");//注意名字必须为token才能获取到jwt
if (StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token字符串获取会员id
* 这个方法也直接从http的请求中获取id的
*
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if (StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String) claims.get("id");
}
/**
* 解析JWT
*
* @param jwt
* @return
*/
public static Claims parseJWT(String jwt) {
Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwt).getBody();
return claims;
}
}
2.JsonResult
package com.alanx.java.util;
import lombok.Data;
import java.io.Serializable;
/**
* @Description: 统一返回实体
*/
@Data
public class JsonResult<T> implements Serializable {
private Boolean success;
private Integer errorCode;
private String errorMsg;
private T data;
public JsonResult() {
}
public JsonResult(boolean success) {
this.success = success;
this.errorCode = success ? ResultCode.SUCCESS.getCode() : ResultCode.COMMON_FAIL.getCode();
this.errorMsg = success ? ResultCode.SUCCESS.getMessage() : ResultCode.COMMON_FAIL.getMessage();
}
public JsonResult(boolean success, ResultCode resultEnum) {
this.success = success;
this.errorCode = success ? ResultCode.SUCCESS.getCode() : (resultEnum == null ? ResultCode.COMMON_FAIL.getCode() : resultEnum.getCode());
this.errorMsg = success ? ResultCode.SUCCESS.getMessage() : (resultEnum == null ? ResultCode.COMMON_FAIL.getMessage() : resultEnum.getMessage());
}
public JsonResult(boolean success, T data) {
this.success = success;
this.errorCode = success ? ResultCode.SUCCESS.getCode() : ResultCode.COMMON_FAIL.getCode();
this.errorMsg = success ? ResultCode.SUCCESS.getMessage() : ResultCode.COMMON_FAIL.getMessage();
this.data = data;
}
public JsonResult(boolean success, ResultCode resultEnum, T data) {
this.success = success;
this.errorCode = success ? ResultCode.SUCCESS.getCode() : (resultEnum == null ? ResultCode.COMMON_FAIL.getCode() : resultEnum.getCode());
this.errorMsg = success ? ResultCode.SUCCESS.getMessage() : (resultEnum == null ? ResultCode.COMMON_FAIL.getMessage() : resultEnum.getMessage());
this.data = data;
}
}
3.ResultCode
package com.alanx.java.util;
/**
* @Description: 返回码定义
* 规定:
* #1表示成功
* #1001~1999 区间表示参数错误
* #2001~2999 区间表示用户错误
* #3001~3999 区间表示接口异常
*/
public enum ResultCode {
/* 成功 */
SUCCESS(200, "成功"),
/* 默认失败 */
COMMON_FAIL(999, "失败"),
/* 参数错误:1000~1999 */
PARAM_NOT_VALID(1001, "参数无效"),
PARAM_IS_BLANK(1002, "参数为空"),
PARAM_TYPE_ERROR(1003, "参数类型错误"),
PARAM_NOT_COMPLETE(1004, "参数缺失"),
/* 用户错误 */
USER_NOT_LOGIN(2001, "用户未登录"),
USER_ACCOUNT_EXPIRED(2002, "账号已过期"),
USER_CREDENTIALS_ERROR(2003, "密码错误"),
USER_CREDENTIALS_EXPIRED(2004, "密码过期"),
USER_ACCOUNT_DISABLE(2005, "账号不可用"),
USER_ACCOUNT_LOCKED(2006, "账号被锁定"),
USER_ACCOUNT_NOT_EXIST(2007, "账号不存在"),
USER_ACCOUNT_ALREADY_EXIST(2008, "账号已存在"),
USER_ACCOUNT_USE_BY_OTHERS(2009, "账号下线"),
/* 业务错误 */
NO_PERMISSION(3001, "没有权限");
private Integer code;
private String message;
ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 根据code获取message
*
* @param code
* @return
*/
public static String getMessageByCode(Integer code) {
for (ResultCode ele : values()) {
if (ele.getCode().equals(code)) {
return ele.getMessage();
}
}
return null;
}
}
4.ResultTool
package com.alanx.java.util;
/**
* @Description: 返回体构造工具
*/
public class ResultTool {
public static JsonResult success() {
return new JsonResult(true);
}
public static <T> JsonResult<T> success(T data) {
return new JsonResult(true, data);
}
public static JsonResult fail() {
return new JsonResult(false);
}
public static JsonResult fail(ResultCode resultEnum) {
return new JsonResult(false, resultEnum);
}
}
三、Controller层
首次登录成功后,将信息存放到Rides中
package com.alanx.java.controller;
import com.alanx.java.bean.Users;
import com.alanx.java.service.UserService;
import com.alanx.java.util.JsonResult;
import com.alanx.java.util.JwtUtils;
import com.alanx.java.util.ResultTool;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/users")
public class UsersController {
@Resource
private UserService service;
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/login")
public String login(Users users) {
QueryWrapper<Users> wrapper = new QueryWrapper<>();
wrapper.eq("username", users.getUserName());
wrapper.eq("password", users.getPassWord());
List<Users> list = service.list(wrapper);
if (list.size() == 0) {
return JSON.toJSONString(ResultTool.fail()); //失败了返回一个错误代码
}
Users u = list.get(0);
String token = JwtUtils.getJwtToken(u);
stringRedisTemplate.opsForValue().set(u.getId() + "", token, 1, TimeUnit.DAYS); //存放到redis中
JsonResult<String> result = ResultTool.success(token);
return JSON.toJSONString(result);
}
}
使用Postman测试一下结果密码错误会返回一个错误代码

密码正确的话,会出现jwt

在Redis中查询结果,复制结果去JWT官网进行解码后就会出现除密码外的信息。


在第二部分载体中可以自定义解码出来的结果,在JwtUtils类中的getJwtToken方法中加入信息

边栏推荐
- Automatic software test - read SMS verification code using SMS transponder and selenium
- Precondition end of script headers or end of script output before headers
- Mongotemplate - distinct use
- Mac installation php7.2
- Adobe Premiere Basics - general operations for editing material files (offline files, replacing materials, material labels and grouping, material enabling, convenient adjustment of opacity, project pa
- 【TcaplusDB知识库】TcaplusDB单据受理-事务执行介绍
- Application and practice of DDD in domestic hotel transaction -- Theory
- When easycvr deploys a server cluster, what is the reason why one is online and the other is offline?
- Adobe Premiere foundation - time remapping (10)
- PostgreSQL database system table
猜你喜欢

Niuke Xiaobai monthly race 52 E group logarithmic sum (inclusion exclusion theorem + dichotomy)

Abc253 D fizzbuzz sum hard (tolerance exclusion theorem)

VB. Net read / write NFC ntag tag source code

Spingmvc requests and responses

ISO 32000-2 international standard 7.7

Travel card "star picking" hot search first! Stimulate the search volume of tourism products to rise

jdbc_相關代碼

Software testing - you may not understand the basic theoretical knowledge

NVIDIA installs the latest graphics card driver

Adobe Premiere Foundation - réglage du son (correction du volume, réduction du bruit, tonalité téléphonique, changement de hauteur, égaliseur de paramètres) (XVIII)
随机推荐
Does rapid software delivery really need to be at the cost of security?
How to use idea?
MySql存储过程循环的使用分析详解
Goldfish rhca memoirs: do447 building advanced job workflow -- using fact cache to improve performance
PWM output experiment based on stm32f103zet6 library function
[tcapulusdb knowledge base] tcapulusdb operation and maintenance doc introduction
Proxmox VE Install 7.2
Top 30 open source software
If the evaluation conclusion of waiting insurance is poor, does it mean that waiting insurance has been done in vain?
js两个一维数组合并并去除相同项(整理)
Xiaobai yuesai 51 supplement e g f
VMware installation esxi
[target tracking] |stark configuration win OTB
Adobe Premiere foundation - batch material import sequence - variable speed and rewind (recall) - continuous action shot switching - subtitle requirements (13)
NVIDIA installs the latest graphics card driver
SSH protocol learning notes
[tcapulusdb knowledge base] tcapulusdb doc acceptance - create business introduction
The soft youth under the blessing of devcloud makes education "smart" in the cloud
Issue 42: is it necessary for MySQL to have multiple column partitions
Adobe Premiere基础-素材嵌套(制作抖音结尾头像动画)(九)
