当前位置:网站首页>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方法中加入信息

边栏推荐
- 牛客小白月赛52 E 分组求对数和(容斥定理+二分)
- Configure the local domain name through the hosts file
- 软件测试——基础理论知识你都不一定看得懂
- Issue 42: is it necessary for MySQL to have multiple column partitions
- Adobe Premiere基础-不透明度(蒙版)(十一)
- 【TcaplusDB知识库】TcaplusDB单据受理-创建业务介绍
- 3h精通OpenCV(六)-图像堆叠
- JS merge two 2D arrays and remove the same items (collation)
- Relationship among controller, service and Dao
- 等保测评结论为差,是不是表示等保工作白做了?
猜你喜欢

Automatic software test - read SMS verification code using SMS transponder and selenium

Error building SqlSession问题

DevCloud加持下的青软,让教育“智”上云端

Top 30 open source software

Have you grasped the most frequently asked question in the interview about massive data processing?

让 Google 搜索到自己的博客

ABC253 D FizzBuzz Sum Hard(容斥定理)

ISO 32000-2 international standard 7.7

Serial port experiment based on stm32f103zet6 library function

Adobe Premiere基础-不透明度(混合模式)(十二)
随机推荐
Request header field XXXX is not allowed by access control allow headers in preflight response
图像特征计算与表示——基于内容的图像检索
让 Google 搜索到自己的博客
Xiaobai yuesai 51 supplement e g f
3h精通OpenCV(六)-图像堆叠
Mac installation php7.2
3h精通OpenCV(七)-颜色检测
When easycvr deploys a server cluster, what is the reason why one is online and the other is offline?
Image feature computation and representation -- content based image retrieval
WBF:检测任务NMS后虑框新方式?
【TcaplusDB知识库】TcaplusDB运维单据介绍
Xiaomai technology x hologres: high availability of real-time data warehouse construction of ten billion level advertising
ISO 32000-2 international standard 7.7
lodash深拷贝使用
codeforces每日5题(均1700)-第二天
通过 hosts文件配置本地域名
[tcapulusdb knowledge base] tcapulusdb doc acceptance - transaction execution introduction
Abc253 D fizzbuzz sum hard (tolerance exclusion theorem)
EasyCVR部署服务器集群时,出现一台在线一台不在线是什么原因?
shell教程之循环语句for,while,until用法
