jwt学习笔记
jwt是json web token的缩写,常用于安全校验
jwt的组成
jwt有三部分组成,用.拼接
这三部分是
-
Header(数据类型和加密算法类型)
{ 'typ': 'JWT', 'alg': 'HS256' } -
Payload (存放有效信息)
{ 'sub': '1234567890', 'name': 'john', 'admin': true } -
signatrue 对前两个部分进行再编码
var encodeString = base64UrlEncode(header) + '.' + base64UrlEncode(payload) var signatrue = HMACSHA256(encodedString, 'secret')
依赖
io.jsonwebtoken
jjwt
0.9.1
javax.xml.bind
jaxb-api
2.3.0
com.sun.xml.bind
jaxb-impl
2.3.0
com.sun.xml.bind
jaxb-core
2.3.0
javax.activation
activation
1.1.1
创建一个jwt
package zjc;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.UUID;
public class Test {
private long time = 1000 * 60 * 60 * 24;
private String signature = "dasdia";
@org.junit.Test
public void test() {
JwtBuilder jwtBuilder = Jwts.builder(); // 构建jwt对象
String token = jwtBuilder
// header
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
// payload
.claim("username", "张三")
.claim("role", "admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis() + time)) // 有效期
.setId(UUID.randomUUID().toString())
// signature
.signWith(SignatureAlgorithm.HS256, signature)
.compact();
System.out.println(token);
}
}
运行获得以下token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2MzQwMTU0MDgsImp0aSI6IjRjMWJiZGZlLTRkNzMtNDJmOS05NzE3LTZjOWE5NGI3NTBhNSJ9.CcDS6k2vcfz_ajUlhHtGhJEm_VzzohzLXJaAIylB-Eo
同样的,有token和signature就可以从token中获取数据
@org.junit.Test
public void parse() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2MzQwMTU0MDgsImp0aSI6IjRjMWJiZGZlLTRkNzMtNDJmOS05NzE3LTZjOWE5NGI3NTBhNSJ9.CcDS6k2vcfz_ajUlhHtGhJEm_VzzohzLXJaAIylB-Eo";
JwtParser parser = Jwts.parser();
Jws claimsJws = parser.setSigningKey(signature).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
System.out.println(claims.get("username"));
System.out.println(claims.get("role"));
System.out.println(claims.getId());
System.out.println(claims.getSubject());
System.out.println(claims.getExpiration());
}
运行结果如下

springboot中使用jwt
-
添加上述依赖
-
创建用户Model

package zjc.jwt_001.entity; import lombok.Data; @Data public class User { private String username; private String password; private String token; } -
创建jwt工具类

package zjc.jwt_001.util; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import java.util.UUID; public class JwtUtil { private static long time = 1000 * 60 * 60 * 24; private static String signature = "dasdia"; public static String createToken() { JwtBuilder jwtBuilder = Jwts.builder(); // 构建jwt对象 return jwtBuilder // header .setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") // payload .claim("username", "张三") .claim("role", "admin") .setSubject("admin-test") .setExpiration(new Date(System.currentTimeMillis() + time)) // 有效期 .setId(UUID.randomUUID().toString()) // signature .signWith(SignatureAlgorithm.HS256, signature) .compact(); } } -
添加相应的controller

package zjc.jwt_001.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import zjc.jwt_001.entity.User; import zjc.jwt_001.util.JwtUtil; @RestController public class UserController { private final String USERNAME = "admin"; private final String PASSWORD = "123456"; @GetMapping("/login") public User login(User user) { if (USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())) { user.setToken(JwtUtil.createToken()); return user; // 验证成功 } return null; } } -
跨域设置
package zjc.jwt_001.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfiguration implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600) .allowedHeaders("*"); } } -
测试访问
访问
localhost:8080/login其中用户名和密码设定如下

访问页面

获取如下数据
{ "username": "admin", "password": "123456", "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IuW8oOS4iSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2MzQwMTc2MDIsImp0aSI6IjQwMzk2ZWI0LTRkOTEtNDgwYS05YzExLWNiNGUzNzJjZmE5YiJ9.HqMgqiT6CQkZNNBm44KwQsJA8IFa0B6yvBC5wx53jM8" }
springboot + vue
实现功能:
前端登录并且登陆成功之后储存登录信息
创建一个登陆页面
提交
重置
token校验
因为token有有效期,所以需要在页面跳转时对token进行是否失效的校验
后端编写校验工具
在JwtUtil类中添加静态方法
public static boolean checkToken(String token) {
if (token == null) { // token不存在
return false;
}
try {
Jws claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
} catch (Exception e) {
return false;
}
return true; // 看是否能解码token,不能解码说明token无效
}
创建校验token的controller
@GetMapping("/checkToken")
public boolean checkToken(HttpServletRequest request) {
String token = request.getHeader("token");
return JwtUtil.checkToken(token);
}
前端在router增加过滤

增加以下函数
router.beforeEach((to, from, next) => {
if (to.path.startsWith('/login')) {
window.localStorage.removeItem('access-admin') // 如果去登陆页面那就清除本地登录信息
next()
} else {
// 如果是去其他页面那就校验本地登录信息,如果校验结果为true那就继续,为false就跳转到/error页面
let admin = JSON.parse(window.localStorage.getItem('access-admin'))
if (!admin) {
next({path: '/login'})
} else {
axios({
url: 'http://localhost:8080/checkToken',
method: 'get',
headers: {
token: admin.token
}
}).then(resp => {
if (!resp.data) {
console.log('校验失败')
next({path: '/error'})
}
})
next()
}
}
})
创建error页面