jwt生成token 以及token的验证,实现一个账号不能同时多地登录_小趴菜h的博客-爱代码爱编程
<!-- 生成token-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.9.0</version>
</dependency>
工具类
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Slf4j
@Component
public class TokenUtils {
@Autowired
private static HttpServletRequest httpServletRequest;
//密钥
public static final String SECRET = "ShanXiSiKaoZheTongChengDaoJia";
//过期时间:秒
public static final int EXPIRE = 300;
/**
* 生成Token
*/
public static String getToken(String userId,String SECRET){
// //过期时间
// Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面 作为载荷
// .withExpiresAt(DateUtil.offsetHour(new Date(),1)) //两小时后token过期
.withExpiresAt(DateUtil.offsetSecond(new Date(),300)) //两小时后token过期
.sign(Algorithm.HMAC256(SECRET)); // 以 sign 作为 token 的密钥
}
/**
* 验证token
*/
public static DecodedJWT verify(String token) {
//如果有任何验证异常,此处都会抛出异常
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
return decodedJWT;
}
/**
* 获取token中的 payload
*/
public static DecodedJWT getTokenInfo(String token) {
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
// 使用 TokenUtils.getTokenInfo(token).getClaim("account").asString()
return decodedJWT;
}
}
在用户登录系统的时候生成token并放到redis 将token和用户信息返回给前端
//生成token
String token = TokenUtils.getToken(User.getTel(), TokenUtils.SECRET);
redisTemplate.opsForValue().set("token"+User.getTel(), token);
redisTemplate.expire("token"+User.getTel(),300,TimeUnit.MINUTES);
前端在后面的操作将token设置为Header
下面是请求过滤器的请求拦截 以及token的验证 并实现一个账号只能有一个人登录
import com.alibaba.fastjson.JSONObject;
import com.sxskz.chaoliu.pojo.R;
import com.sxskz.chaoliu.util.ValidateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;
/*
* 过滤器
* */
@WebFilter(urlPatterns = {"/api/*"}) ///api/*
public class LoginFilter implements Filter {
@Autowired
RedisTemplate redisTemplate;
@Override
public void init(FilterConfig filterConfig) throws ServletException{
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("项目启动了-----");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*"); //解决跨域访问报错
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600"); //设置过期时间
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With,Content-Type, Accept,token,tel,client_id,identify, uuid, Authorization");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 支持HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // 支持HTTP 1.0. response.setHeader("Expires", "0");
response.setHeader("Access-Control-Expose-Headers","X-forwared-port, X-forwarded-host");
response.setHeader("Vary","Origin,Access-Control-Request-Method,Access-Control-Request-Headers");
//需要放行的端口
String path = "/api/login" +
"/api/insertUser" +
"/api/getCode" +
"api/getYcCode"+
"/api/notify" +
"/order/hrefBack"+
"/api/callback"+
"/api/upLoadHeader" +
"/api/htUserLogin"+
"/api/selectProducts" +
"/api/selectBlindBoxAll";
String token = request.getHeader("token");
System.out.println(">>>>>>>>>>>>>>"+token);
String tel = request.getHeader("tel");
String uri = request.getRequestURI();
if (path.contains(uri)) {
filterChain.doFilter(servletRequest,servletResponse); // 放行请求
}else if (ValidateUtil.isEmpty(token) || ValidateUtil.isEmpty(tel)){
String s = JSONObject.toJSONString(new R("100", null, "请先登录"));
response.setContentType("json/text;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.write(s);
}else {
Long expire = redisTemplate.getExpire("token" + tel);
if (expire <= 0){
String s = JSONObject.toJSONString(new R("300", null, "token过期,请重新登录"));
response.setContentType("json/text;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.write(s);
}else {
String oneToken = (String) redisTemplate.opsForValue().get("token" + tel);
if (!token.equals(oneToken)){
System.out.println("66666666666666666666666666666666666666");
String s = JSONObject.toJSONString(new R("200", null, "该账号已在其他设备登录,请重新登录或修改密码"));
response.setContentType("json/text;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.write(s);
}else{
redisTemplate.expire("token"+tel,60L, TimeUnit.MINUTES);
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
}
@Override
public void destroy() {
}
}
切记这个过滤器操作要在启动类上添加注解@ServletComponentScan //配合过滤器
否则不生效