SpringBoot使用拦截器实现token身份验证
浏览器的传统session会话 无法应用于安卓浏览器 因此需要token身份验证 我这里使用拦截器配合Redis实现此功能
AuthorizationInterceptor类:
package com.ls.reg.config;
import com.ls.reg.bin.base.Result;
import com.ls.reg.utils.JSONUtilsEx;
import com.ls.reg.utils.RedisUtilsEx;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
response.setHeader("Access-Control-Allow-Origin", "*");//开发环境允许跨域
//如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Enumeration enu = request.getParameterNames();
List<String> list = new ArrayList();
String user_token = "";
while (enu.hasMoreElements()) {
String paraName = (String) enu.nextElement();
if(paraName.equals("user_token")) {
user_token = request.getParameter(paraName);
list.add(request.getParameter(paraName));
} else {
list.add(request.getParameter(paraName));
}
}
if (method.getAnnotation(MustLogin.class) != null) {
// 如果 加这个注解了 说明用户 必须要登录 必须传 user_token
if(StringUtils.isBlank(user_token)) {
Result result = new Result(Result.NOLOGIN,"请登录", "");
String serialize = JSONUtilsEx.serialize(result);
returnErrorMessage(response,serialize);
return false;
}else {
String string = RedisUtilsEx.get("session-"+user_token);
if(StringUtils.isBlank(string)) {
// 缓存里面不存在 就说明 用户信息 失效
//response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
Result result = new Result(Result.NOLOGIN,"请登录", "");
String serialize = JSONUtilsEx.serialize(result);
returnErrorMessage(response,serialize);
return false;
}else {
// 重新登录 要刷新下 用户 user-token //(10小时不操作自动掉线)
RedisUtilsEx.set("session-"+user_token, string,60*60*10);
}
}
}
return true;
}
private void returnErrorMessage(HttpServletResponse response, String errorMessage) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(errorMessage);
out.flush();
}
}
注意 需要将以上拦截器在WebMvcConfigurer中注册:
package com.ls.reg.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MySpringBootConfig implements WebMvcConfigurer {
@Autowired
private AuthorizationInterceptor interceptor;
/**
* 加载拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// super.addInterceptors(registry);
InterceptorRegistration loginRegistry = registry.addInterceptor(interceptor);
loginRegistry.excludePathPatterns("/init/**");
}
/**
* 配置static的静态资源访问
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
}
注解 MustLogin
package com.ls.reg.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MustLogin {
}
在登录接口中向缓存中加入user_token并将其返回给前端,前端使用本地储存或者其他的存储方式将其存储,在访问其他需要身份验证的接口时将其作为入参传入即可
String userToken = StaticUtils.getUserToken();//此处的token是UUID
String oldToken = RedisUtilsEx.get("session-user");
if(StringUtils.isNotBlank(oldToken)) {
//要删除以前的token
//RedisUtilsEx.del("session-"+oldToken);
}
RedisUtilsEx.set("session-"+userToken, userId, 60*60*10);
RedisUtilsEx.set("session-user-"+userId, userToken, 60*60*10);
return userToken;
那么接下来 只需要在必须登录才可访问的接口中加上此注解 即可实现身份登录验证
@PostMapping(value="/checkLogin")
@MustLogin
public Result checkLogin(
String user_token
) {
try {
Integer userId = Integer.parseInt(RedisUtilsEx.get("session-"+user_token));
return new Result(Result.OK,"验证成功",userId);
} catch (Exception e) {
e.printStackTrace();
return new Result(Result.ERROR, e.getMessage(), "");
}
}