简单实现思路
1.用户登录成功之后,JWTCreator按照一定规则编码生成一个token,token中包含用户标识以及设定的失效时间,token存储到Cookie中
2.将用户信息存到Redis中,redis设定的key包含用户标识符
3.自定义注解,每一个需要用户验证的控制器接口、页面添加此注解
下面是具体实现
创建一个TokenUti类
package com.demo.manage.common.tools.utils.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Map;
/**
* @author qiqiyu
* @description
* @date 2022/4/28
*/
public class TokenUtil {
public static final String signature = "demo";
public static final String subject = "demo";
/**
* create token
* @param hashMap
* @return
*/
public static String createToken(Map<String, String> hashMap){
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE,1);
JWTCreator.Builder builder = JWT.create();
hashMap.forEach((k,v)->builder.withClaim(k,v));
String token = builder.withExpiresAt(calendar.getTime()).withSubject(subject).sign(Algorithm.HMAC256(signature));
return token;
}
/**
* verify token
* @param token
* @return
*/
public static DecodedJWT verifyToken(String token){
return JWT.require(Algorithm.HMAC256(signature)).build().verify(token);
}
/**
* decode token by verify
* @param token
* @return
*/
public static DecodedJWT decodedToken(String token){
DecodedJWT decodedJWT = null;
try{
decodedJWT = verifyToken(token);
} catch (Exception e){
} finally {
return decodedJWT;
}
}
}
创建自定义注解以及Handler
package com.demo.manage.common.annotation;
import java.lang.annotation.*;
/**
* @author qiqiyu
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginCheck {
}
package com.demo.manage.common.config;
import com.demo.manage.common.annotation.LoginCheck;
import com.demo.manage.common.constant.RedisConstants;
import com.demo.manage.common.utils.RedisUtil;
import com.demo.manage.common.utils.ServletUtil;
import com.demo.manage.web.domain.Members;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* @author qiqiyu
* @description
* @date 2021/12/7
*/
public class LoginInterceptorConfig implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
RedisUtil redisUtil = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext()).getBean(RedisUtil.class);
//判断请求的方法上是否有注解
boolean haveAnnotation = handler.getClass().isAssignableFrom(HandlerMethod.class);
String url = request.getRequestURI();
if (haveAnnotation) {
// 强转
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取方法
Method method = handlerMethod.getMethod();
if (!method.isAnnotationPresent(LoginCheck.class)) {
return true;
}
//如果有注解,判断是否是MyAnnotation
LoginCheck ma = method.getAnnotation(LoginCheck.class);
//如果存在该注解
if (null != ma) {
//获得名为member的对象
Members members = ServletUtil.getLoginMember();
if (null == members) {
//如果不是转发到/index上
response.sendRedirect("/login?frontUrl="+url);
return false;
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
ServletUtil中的实现
public static Members getLoginMember() {
String token = getCookie("token");
if (null == token) {
return null;
}
DecodedJWT dj = TokenUtil.decodedToken(token);
if(null == dj){
return null;
}
String userKey= dj.getClaim("userKey").asString();
if (StringUtil.isNotBlank(userKey)) {
Object o = redisUtil.get("member:demo" + userKey);
if (null != o) {
Members members = (Members) o;
return members;
}
}
return null;
}
// 获取cookie中的属性值
public static String getCookie(String var) {
Cookie[] cookies = getRequest().getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(var)) {
return cookie.getValue();
}
}
}
return null;
}
登录实现
@PostMapping("/login")
@ResponseBody
public R login(String phone, String password,HttpServletResponse response) {
Map mapMember = new HashMap(1);
if (StringUtil.isBlank(memberVo.getPhone())) {
return R.warn("请输入账号");
}
//获取用户信息
Members members = membersMapper.selectMembersByPhone(phone);
if (StringUtil.isEmpty(password)) {
return R.warn("请输入密码");
}
if (Objects.isNull(members)) {
return R.warn("用户不存在");
}
//校验密码
if (!PasswordUtil.checkPassWord(password, members.getPassword())) {
return R.warn("用户名或密码不正确");
}
mapMember.put("userKey", members.getUserKey());
String token = TokenUtil.createToken(mapMember);
redisUtil.set("member:demo" + members.getUserKey(), members, 3600);
Cookie cookie = new Cookie("token", value);
cookie.setMaxAge(3600);
cookie.setPath("/");
response.addCookie(cookie);
return R.ok();
}
自定义接口的使用
@LoginCheck
@GetMapping("/demo-page")
public String demoPage(ModelMap mmp) {
return "/demo/page";
}