基本思路:
客户端发起登录请求到后端服务器,验证用户名和密码后,生成jwt令牌返回给客户端,把一些不敏感的信息存入到jwt的载荷中,由客户端自行存储这个令牌,以后的每次请求都要携带这个jwt令牌,我们称为token,再创建一个拦截器拦截除了登录外的所有请求,在这个拦截器中我们要验证token的合法性,然后解析出载荷信息,放入到当前线程当中,方便在后面的业务中会用。
注意:
默认采用手机号码后6位作为密码,使用md5加密后的密码。
代码如下:
登录部分:
@Override
public String login(LoginDto loginDto) {
//判空
if(loginDto == null){
throw new CustomerException(ResultEnum.USERNAME_OR_PASSWORD_ERROR);
}
//查询用户信息
LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Admin::getUsername,loginDto.getUsername());
Admin admin = getBaseMapper().selectOne(queryWrapper);
if(admin == null){
throw new CustomerException(ResultEnum.USER_NOT_EXIT);
}
//将获取到的盐和用户输入的密码进行md5加密并与数据库中的密码进行对比
String salt = admin.getSalt();
String md5Password = DigestUtil.md5Hex(loginDto.getPassword() + salt);
if(!md5Password.equals(admin.getPassword())){
throw new CustomerException(ResultEnum.USERNAME_OR_PASSWORD_ERROR);
}
//生成jwt类型的token返回给客户端
HashMap<String, Object> payload = new HashMap<>();
payload.put("id",admin.getId());
payload.put("name",admin.getName());
payload.put("username",admin.getUsername());
payload.put("image",admin.getImage());
payload.put("phone",admin.getPhone());
payload.put("expire",System.currentTimeMillis() + 1000 * 60 * 60 *2);
String token = TokenUtils.createToken(payload);
return token;
}
编写拦截器:
public class AuthInterceptor implements HandlerInterceptor {
/**
* 处理器执行之前
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//获取token
String token = httpServletRequest.getHeader("token");
if(StringUtils.isEmpty(token)){
token = httpServletRequest.getParameter("token");
if(StringUtils.isEmpty(token)){
Result rs = Result.buildFail(ResultEnum.TOKEN_NOT_EMPTY);
ResponseUtils.responseToJson(httpServletResponse, JsonUtils.objectToJson(rs));
return false;
}
}
//校验jwt的合法性
if(!JWTUtil.verify(token, TokenUtils.KEY.getBytes())){
Result rs = Result.buildFail(ResultEnum.TOKEN_ERROR);
ResponseUtils.responseToJson(httpServletResponse, JsonUtils.objectToJson(rs));
return false;
}
JWT jwt = JWTUtil.parseToken(token);
NumberWithFormat expire = (NumberWithFormat) jwt.getPayload("expire");
if(System.currentTimeMillis() > expire.longValue()){
Result rs = Result.buildFail(ResultEnum.TOKEN_EXPIRE);
ResponseUtils.responseToJson(httpServletResponse, JsonUtils.objectToJson(rs));
return false;
}
HashMap<String, Object> payload = new HashMap<>();
payload.put("id",jwt.getPayload("id"));
payload.put("name",jwt.getPayload("name"));
payload.put("username",jwt.getPayload("username"));
payload.put("image",jwt.getPayload("image"));
payload.put("phone",jwt.getPayload("phone"));
AdminThreadLocal.set(payload);
return true; //true放行,false拦截
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
AdminThreadLocal.remove();
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
配置拦截器:
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/login"/>
<bean class="com.gxa.op.permisson.AuthInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
使用到的工具类:
public class AdminThreadLocal {
private static ThreadLocal<Map<String,Object>> tl = new ThreadLocal<>();
/**
* 绑定当前线程
*/
public static void set(Map<String,Object> map){
tl.set(map);
}
/**
* 获取当前线程
*/
public static Map<String,Object> get(){
return tl.get();
}
/**
* 移除当前线程绑定的用户信息
*/
public static void remove(){
tl.remove();
}
}
public class TokenUtils {
public static final String KEY = "dnjsdfhjdvhdjvnbjxcbjhcbvsdhjajdejihsfnj";
public static String createToken(Map<String,Object> payload){
return JWTUtil.createToken(payload,KEY.getBytes());
}
}
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>xxx</version>
</dependency>
此文章仅作为学习记录