TokenUtil
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.stereotype.Component;
import vip.jiupiao.admin.table.tables.pojos.SysUserEntity;
import vip.jiupiao.common.service.common.JsonUtil;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Component
public class TokenUtil {
/**
* 根据用户信息生成token
*
* @param sysUserEntity
* @return
*/
public static String createToken(SysUserEntity sysUserEntity) {
return JWT.create()
// 请求头
.withHeader(new HashMap<>() {
{
put("typ", "JWT");
put("alg", "HS256");
}
})
// 负载属性
.withClaim("obj", JsonUtil.writeValue(sysUserEntity))
// 签发时间
.withIssuedAt(new Date())
// 过期时间
.withExpiresAt(new Date(System.currentTimeMillis() + 30 * TokenKey.MINUTES))
// 加密算法 密钥
.sign(Algorithm.HMAC256(TokenKey.TOKEN_KEY));
}
/**
* 校验token
*
* @param token
* @return
*/
public static Map<String, Claim> verify(String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TokenKey.TOKEN_KEY)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return jwt.getClaims();
}
/**
* 根据token解析用户信息
*
* @param token
* @return
*/
public static SysUserEntity getSysUserEntity(String token) {
Map<String, Claim> claimMap = TokenUtil.verify(Objects.requireNonNull(token));
String obj = claimMap.get("obj").asString();
return JsonUtil.readValue(obj, new TypeReference<>() {
});
}
public static void main(String[] args) {
TokenUtil tokenUtil = new TokenUtil();
SysUserEntity sysUserEntity = new SysUserEntity();
sysUserEntity.setId(1L);
sysUserEntity.setUsername("zhangSan");
String token = tokenUtil.createToken(sysUserEntity);
// 生成的token
System.out.println(token);
// 解析token获取负载
System.out.println(getSysUserEntity(token));
}
}
MyHandlerInterceptor
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import vip.jiupiao.common.constants.exception.ErrorCode;
import vip.jiupiao.common.constants.model.ResponseData;
import vip.jiupiao.common.service.common.JsonUtil;
import vip.jiupiao.utils.StringUtil;
import java.io.PrintWriter;
@Component
public class MyHandlerInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 请求头中获取token
String token = request.getHeader("token");
if (StringUtil.isNotEmpty(token)) {
// token存在
String redisKey = TokenKey.REDIS_KEY + TokenUtil.getSysUserEntity(token).getUsername();
if (token.equals(redisTemplate.opsForValue().get(redisKey))) {
return true;
} else {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
ResponseData<Object> resp = ResponseData.of(ErrorCode.notLoggedIn);
out.write(JsonUtil.writeValue(resp));
return false;
}
} else {
// 没有token
response.setContentType("application/json;charset=utf-8");
ResponseData<Object> resp = ResponseData.of(ErrorCode.authUnauthorized);
response.getWriter().write(JsonUtil.writeValue(resp));
return false;
}
}
}
WebConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private MyHandlerInterceptor handlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(handlerInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/sysUser/loginSysUser")
;
}
}
TokenKey
public class TokenKey {
/**
* redis token 前缀
*/
public static final String REDIS_KEY = "jp:token:token_";
/**
* 分钟
*/
public static final long MINUTES = 1000 * 60;
/**
* token 密钥
*/
public static final String TOKEN_KEY = "my_secret";
}
SysUserController
@RequestMapping("sysUser")
@RestController
public class SysUserController {
@Autowired
SysUserService sysUserService;
@PostMapping("/loginSysUser")
public ResponseData loginSysUser(@RequestBody SysUserEntity sysUserEntity) {
return sysUserService.loginSysUser(sysUserEntity);
}
@PostMapping("/logoutSysUser")
public ResponseData logoutSysUser(@RequestBody SysUserEntity sysUserEntity) {
return ResponseData.exec(sysUserService.logoutSysUser(sysUserEntity));
}
}
sysUserService
@Service
public class SysUserServiceImpl implements SysUserService{
@Override
public ResponseData loginSysUser(SysUserEntity sysUserEntity) {
String token = request.getHeader("token");
if (StringUtil.isNotEmpty(token)) {
// token存在,到redis中查询是否过期
if (Boolean.TRUE.equals(redisTemplate.hasKey(TokenKey.REDIS_KEY + sysUserEntity.getUsername()))) {
return ResponseData.exec(SysErrorCode.restrictLoginError);
}
}
SysUserEntity entity = sysUserDao.selectSysUserByUsername(sysUserEntity.getUsername());
if (Objects.nonNull(entity)) {
if (entity.getStatus() != SysStatusType.ENABLE.getCode()) {
return ResponseData.exec(SysErrorCode.userDisableError);
}
// 校验密码
boolean equals = entity.getPassword().equals(DigestUtil.sha256Hex(sysUserEntity.getPassword() + entity.getSalt()));
if (equals) {
entity.setPassword("");
entity.setSalt("");
String aToken = TokenUtil.createToken(entity);
response.setHeader("token", aToken);
// 添加token到redis中
CompletableFuture.runAsync(() -> redisTemplate.opsForValue().set(TokenKey.REDIS_KEY + entity.getUsername(), aToken, 30L, TimeUnit.MINUTES));
// 更新登录ip和最后登录时间
CompletableFuture.runAsync(() -> updateSysUserIpLoginDate(entity));
return ResponseData.exec(OpCode.success);
}
}
return ResponseData.exec(SysErrorCode.accountOrPasswordError);
}
@Override
public ResponseData logoutSysUser(SysUserEntity sysUserEntity) {
String token = request.getHeader("token");
if (StringUtil.isNotEmpty(token)) {
// 从token中解析出用户信息
SysUserEntity entity = TokenUtil.getSysUserEntity(token);
// 取前缀和用户名为redis key
String redisKey = TokenKey.REDIS_KEY + entity.getUsername();
if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
redisTemplate.delete(redisKey);
return ResponseData.exec(OpCode.success);
}
}
return ResponseData.exec(SysErrorCode.statusError);
}
}
未登录
登录
登录请求(/sysUser/loginSysUser)在WebConfig中放过 token为null
根据用户名查用户信息
校验密码
根据用户信息生成token
放入Header中
添加token到redis中
其他请求需要带token到请求头中
请求头中token存在
redis中token存在
比较后相等
放行
注销
注销也需要带token到请求头
token拦截
redis比较
比较token
删除token
再带token访问
和redis的token比较 不同
还有个token过期的问题