简述JWT并使用springboot集成
what
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于 Json 的开放标准。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。
why
session:几年前比较常用的身份认证技术,主要在服务器存储一个session
- 用户发送请求时将认证信息一起发到服务端,服务端获取到对应session,就可以认证用户身份
- 用户量一大,服务器存储的session就会增多,相应的服务器压力也会增大
- 单点登录,实现起来比较局限,如果系统的域名不在同一父域下,就不能将cookie携带发给服务端
token:
- 用户登录,服务器给客户端返回一个token,服务器也不用去记录这个token,服务端的压力就会小很多
- 客户端每次发送请求时,只要将此token携带到headers里面,服务算拿到token进行解析,就可认证用户身份
- 单点登录,没有父域名限制,灵活性更强
how
这里只是搭建一个简单的例子,可根据自己的实际情况进行修改
talk is cheap, show you the code
新建springboot项目,先pom引入jwt相关依赖:
<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.7.0</version>
</dependency>
新建如下几个实体类:
@Data
public class CheckResult {
private boolean success;
private Claims claims;
private String errCode;
}
@Data
@AllArgsConstructor
public class User {
private String userName;
private String password;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
编写工具类:
package com.glodon.jwt.utils;
import com.glodon.jwt.entity.CheckResult;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
/**
* @Author: yinjw-b
* @Date: 2021/1/25 15:03
* @Description:
*/
public class JwtUtils {
/**
* 签发Jwt
* @param id
* @param subject 可以是JSON数据 尽可能少
* @param ttlMills
* @return
*/
public static String createJWT(String id, String subject, long ttlMills){
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMills = System.currentTimeMillis();
Date now = new Date(nowMills);
SecretKey secretKey = generalKey();
JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject) // 主题
.setIssuer("user") // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey); // 签名算法及密钥
if(ttlMills >= 0){
long expMills = nowMills + ttlMills;
Date expDate = new Date(expMills);
builder.setExpiration(expDate); // 过期时间
}
return builder.compact();
}
/**
* 生成密钥
* @return
*/
public static SecretKey generalKey(){
byte[] encodeKey = Base64.decode("JaveeSec");
SecretKey key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
return key;
}
/**
* 验证JWT
* @param jwtStr
* @return
*/
public static CheckResult validateJwt(String jwtStr){
CheckResult checkResult = new CheckResult();
Claims claims = null;
try {
claims = parseJWT(jwtStr);
checkResult.setSuccess(true);
checkResult.setClaims(claims);
} catch (ExpiredJwtException e) {
checkResult.setErrCode("JWT_ERRCODE_EXPIRE");
checkResult.setSuccess(false);
} catch (SignatureException e) {
checkResult.setErrCode("JWT_ERRCODE_FAIL");
checkResult.setSuccess(false);
} catch (Exception e) {
checkResult.setErrCode("JWT_ERRCODE_FAIL");
checkResult.setSuccess(false);
}
return checkResult;
}
/**
* 解析JWT字符串
* @param jwt
* @return
*/
public static Claims parseJWT(String jwt){
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
}
编写测试类:
package com.glodon.jwt.controller;
import com.glodon.jwt.entity.CheckResult;
import com.glodon.jwt.entity.User;
import com.glodon.jwt.utils.JwtUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @Author: yinjw-b
* @Date: 2021/1/25 15:33
* @Description:
*/
@RestController
@RequestMapping("/jwt")
public class LoginController {
// 模拟的用户信息
private static List<User> users = new ArrayList<>();
static{
users.add(new User("yinjw", "yinjw"));
users.add(new User("yinwei", "yinwei"));
users.add(new User("Javee", "Javee"));
}
@PostMapping("/login")
public String login(String username, String password){
Optional<User> first = users.stream().filter(user1 -> user1.getUserName().equals(username)).findFirst();
if(first.isPresent()){
User user = first.get();
if(user.getPassword().equals(password)){
//把token返回给客户端-->客户端保存至cookie-->客户端每次请求附带cookie参数
String JWT = JwtUtils.createJWT("1", username, 1611560404241l);
return "success: " + JWT;
}else{
return "error";
}
}else{
return "error";
}
}
@PostMapping("/description")
public CheckResult description(String jwt) {
return JwtUtils.validateJwt(jwt);
}
}
使用postman做一个简单的测试:
登录成功,就返回了token
将token传给服务端,服务器解析后,返回相应的用户信息
写到了这里,大伙就可以用jwt做好多好玩的东西了,比如单点登录之类的