将业务层的token处理,进行统一处理
如何统一处理?
自定义拦截器类实现HandlerInterceptor接口进行拦截
统一处理token后,业务层如何获取user信息?
本地线程ThreadLocal存储user信息,业务层直接可以从ThreadLocal获取user信息
拦截器的使用
1自定义一个类实现HandleInterceptor接口。
2.实现HandLerInterceptor接口的三个方法:
-preHandle():在目标方法之前执行,一般用于预处理(在请求进入controller之前处理)
- postHandle():在目标方法执行之后执行,一般用于后处理
- afterCompletion():整个请求处理完毕,在视图渲染完毕时回调,一般用于资源的清理或性能的统计
3.在springboot中注册拦截器并使用
ThreadLocal
UserHolder工具类(提供两个方法getUser() getUserId())
ThreadLocal<User> threadLocal=new ThreadLocal<T> (
threadLocal.set();//将数据绑定到当前线程
threadLocal.get();//从当前线程中获取数据
统一处理token实现分析
1.UserHolder工具类(提供两个方法getUser() getUserId())
2.修改拦截器-编写拦截业务逻辑
a.根据request对象获取请求头中的token
b.token如果为空,那么返回401(没有权限访问,需要进行身份验证)
c.token如果不为空,根据token作为key到redis获取用户对象
d.如果用户对象为空,那么返回401
e.如果用户对象不为空,通过UserHoler.setUser()存入ThreadLocal return true;
3.修改controller将token参数删除//之前的代码中直接传入token
4.修改service将token处理代码删除,替换为UserHoler.getUserserId()//之前的代码中直接传入token
utils
JwtUtils
package com.tanhua.server.utils;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtils {
@Value("${tanhua.secret}")
private String secret;
/**
* 生成JWT
*
* @return
*/
public String createJWT(String phone,Long userId) {
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("mobile", phone);
claims.put("id", userId);
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)//过期时间 立马过期
.signWith(SignatureAlgorithm.HS256, secret);
return builder.compact();
}
}
interceptor(拦截器)
TokenInterceptor
package com.tanhua.server.interceptor;
import com.tanhua.domain.db.User;
import com.tanhua.server.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器
*/
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
/**
* 进入controller之前执行此方法
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//a.根据request对象获取请求头中token
String headToken = request.getHeader("Authorization");
//b.token如果为空直接返回401(用户没有访问权限,需要进行身份认证。)
if (StringUtils.isEmpty(headToken)) {
response.setStatus(401);
return false;
}
//c.token如果不为空,根据token作为key到redis中获取用户对象
User user = userService.getUserByToken(headToken);
//d.如果用户对象为空,返回401
if (StringUtils.isEmpty(user)) {
response.setStatus(401);
return false;
}
//e.如果用户对象不为空,通过UserHoler.setUser()存入ThreadLocal return true;
UserHolder.setUser(user);
log.debug("user{}*************拦截执行结束了*************",user.toString());
return true;
}
}
WebConfig
package com.tanhua.server.config;
import com.tanhua.server.interceptor.TokenInterceptor;
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;
/**
* 拦截器配置类 类似于springmvc.xml中拦截器配置
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
/**
*
* 将自定义拦截器添加spring容器中
* @param registry
*/
public void addInterceptors(InterceptorRegistry registry) {
//哪些请求要拦截 哪些请求放行(登录-登录第一步---获取验证码 登录第二步---注册登录)
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/user/login","/user/loginVerification");
}
}
UserHolder
package com.tanhua.server.interceptor;
import com.tanhua.domain.db.User;
/**
* 登陆用户信息持有者
* 通过ThreadLocal的形式,存储登陆用户的数据
*/
public class UserHolder {
private static ThreadLocal<User> userThreadLocal = new ThreadLocal<User>();
/**
* 向当前线程中存入用户数据
* @param user
*/
public static void setUser(User user){
userThreadLocal.set(user);
}
/**
* 从当前线程中获取用户数据
* @return
*/
public static User getUser(){
return userThreadLocal.get();
}
/**
* 获取登陆用户的id
* @return
*/
public static Long getUserId(){
return userThreadLocal.get().getId();
}
}