学习一下springboot集成JWT(json web token),了解一下它的整个流程,并运用他,至少让我们的接口不再裸奔。,立志工具人。一起干饭!
本章主要内容
- JWT认证流程
- SpringBoot整合JWT
- 测试
- 使用端到端的JWT创建和验证的Java库 JJWT
- JWT token过期自动续期解决方案
1.JWT认证流程
![](https://img.haomeiwen.com/i19048787/c5c7fd72ff1ec181.png)
- 应用程序或客户端向授权服务器请求授权。这是通过不同的授权流程之一执行的。例如,典型的符合OpenID Connect的Web应用程序将
/oauth/authorize
使用授权代码流通过端点。 - 授予授权后,授权服务器会将访问令牌返回给应用程序。
- 应用程序使用访问令牌来访问受保护的资源(例如API)。
2.SpringBoot整合JWT
2.1.pom.xml引入jar包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
2.2.新建Jwt工具类
用户登录的时候,根据用户信息生成token并返回给用户,用户请求携带token,通过过滤器,使用token反解析出用户信息
Jwt工具类进行token的生成和认证,工具类代码如下:
- 用户登录,获取token并返回
package com.ptdot.mall.controller;
import com.ptdot.mall.common.JwtUtil;
import com.ptdot.mall.compont.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 登录Controller
* @author Administrator
*/
@Slf4j
@RestController
public class LoginController {
@Resource
private JwtUtil jwtUtil;
static Map<Integer, User> userMap = new HashMap<>();
static {
//模拟数据库
User user1 = new User(1, "zhangsan", "张三", "123456");
userMap.put(1, user1);
User user2 = new User(2, "lisi", "李四", "123123");
userMap.put(2, user2);
}
/**
* 模拟用户 登录
*/
@RequestMapping("/login")
public String login(User user) {
for (User dbUser : userMap.values()) {
if (dbUser.getUsername().equals(user.getUsername()) && dbUser.getPassword().equals(user.getPassword())) {
log.info("登录成功!生成token!");
return jwtUtil.createToken(dbUser);
}
}
return "";
}
}
- 获取token的方法&校验token的方法
package com.ptdot.mall.common;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.ptdot.mall.compont.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author Administrator
*/
@Slf4j
@Component
public class JwtUtil {
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.tokenHead}")
private String tokenHead;
/**
* 生成用户token,设置token超时时间
*/
public String createToken(User user) {
//过期时间
Date expireDate = new Date(System.currentTimeMillis() + expiration * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create()
// 添加头部
.withHeader(map)
//可以将基本信息放到claims中
//userId
.withClaim("id", user.getId())
//userName
.withClaim("username", user.getUsername())
//name
.withClaim("name", user.getName())
//超时设置,设置过期的日期
.withExpiresAt(expireDate)
//签发时间
.withIssuedAt(new Date())
//SECRET加密
.sign(Algorithm.HMAC256(secret));
return token;
}
/**
* 校验token并解析token
*/
public Map<String, Claim> verifyToken(String token) {
DecodedJWT jwt;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
log.error(e.getMessage());
log.error("token解码异常");
//解码异常则抛出异常
return null;
}
return jwt.getClaims();
}
}
- 用户登录的方法
package com.ptdot.mall.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* 需要登录后才能访问
* @author Administrator
*/
@Slf4j
@RestController
public class SecureController {
/**
* 查询 用户信息,登录后才能访问
*/
@RequestMapping("/secure/getUserInfo")
public String login(HttpServletRequest request) {
Integer id = (Integer) request.getAttribute("id");
String name = request.getAttribute("name").toString();
String userName = request.getAttribute("username").toString();
return "当前用户信息id=" + id + ",name=" + name + ",username=" + userName;
}
}
- 过滤器 获取到token将token解析为想要的信息
package com.ptdot.mall.common;
import com.auth0.jwt.interfaces.Claim;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* JWT过滤器,拦截 /secure的请求
* @author Administrator
*/
@Slf4j
@WebFilter(filterName = "JwtFilter", urlPatterns = "/secure/*")
public class JwtFilter implements Filter {
@Resource
private JwtUtil jwtUtil;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
response.setCharacterEncoding("UTF-8");
//获取 header里的token
final String token = request.getHeader("authorization");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
chain.doFilter(request, response);
}
// Except OPTIONS, other request should be checked by JWT
else {
if (token == null) {
response.getWriter().write("没有token!");
return;
}
Map<String, Claim> userData = jwtUtil.verifyToken(token);
if (userData == null) {
response.getWriter().write("token不合法!");
return;
}
Integer id = userData.get("id").asInt();
String name = userData.get("name").asString();
String userName = userData.get("username").asString();
//拦截器 拿到用户信息,放到request中
request.setAttribute("id", id);
request.setAttribute("name", name);
request.setAttribute("username", userName);
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
}
}
- yml配置
jwt:
tokenHeader: Authorization #JWT存储的请求头
secret: mall-portal-secret #JWT加解密使用的密钥
expiration: 604800 #JWT的超期限时间(60*60*24*7)
tokenHead: 'Bearer ' #JWT负载中拿到开头
- 启动器配置
package com.ptdot.mall;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* @author Administrator
*/
@ServletComponentScan(basePackages = {"com.ptdot.mall"})
@SpringBootApplication
public class MallApplication {
public static void main(String[] args) {
SpringApplication.run(MallApplication.class, args);
}
}
3.测试
- jwt生成token测试
http://localhost:8080/login?username=zhangsan&password=123456
![](https://img.haomeiwen.com/i19048787/2f43bb402e891ff9.png)
- jwt校验token测试
http://localhost:8080/secure/getUserInfo
Authorization eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOjEsImV4cCI6MTYxNzM0NDM1NiwiaWF0IjoxNjE2NzM5NTU2LCJ1c2VybmFtZSI6InpoYW5nc2FuIn0.Zd9-yxbMTZvopl5sDNMRzyV8wAQQcbhd0xXwtdwkQ6U
![](https://img.haomeiwen.com/i19048787/54a967b122e62266.png)
4.使用端到端的JWT创建和验证的Java库 JJWT
5.JWT token过期自动续期解决方案
不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!
若文章对您有用,请点赞支持哦。
网友评论