无Cookie模式的下登录校验方式
总体流程
- 前端把账号密码给后端校验
- 后端校验完毕后,正确的情况,后端生成token并返回(至于怎么生成token方式有很多,例如:jwt,uuid)
- 前端接受token后,可以把token存在本地(方式很多:Cookie、LocalStorage、SessionStorage),本篇以存入Cookie为例
- 前端每次想后端发请求的时候先从Cookie中取出token,然后放在请求头里面发送过去
- 后端配置一个拦截器,拦截请求,从请求中获取token进行操作
这篇文章是使用的UUID生成一个字符串,然后这个字符串作为redis的key,登录人信息作为redis的value
第一步和第二步不写了,没啥难度
第三步:
把token存入本地Cookie
以js为例(如果你是vue,也可以直接复制使用,vue有自己的设置cookie的方法):
// 存入Cookie并设置过期时间
setCookie(name, value) {
// 获取当前时间
var millisecond = new Date().getTime();
// 设置过期时间,该时间是服务器时间,过期后会自动删除
var expiresTime = new Date(millisecond + 60 * 1000 * 30).toUTCString();
document.cookie = name + "=" + escape(value) + ";path=/;expires=" + expiresTime;
}
// 取出Cookie
getCookie(name) {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)) {
return unescape(arr[2]);
} else {
return null;
}
}
使用vue存入本地Cookie
// todo 后期补
第四步
在拦截器中对每一个请求头添加token
在main.js中操作
使用vue-cookies的话,需要先安装
npm install vue-cookies --save
// cookie
import VueCookies from "vue-cookies";
Vue.use(VueCookies);
// 拦截器中设置 headers 为token
axios.interceptors.request.use(
config => {
let token = VueCookies.get("token");
if (token) {
//这里面获取的请求头的键(tokenHeader)根据每个后端的习惯封装的名称各不相同
config.headers.common['token'] = token
}
return config
}, error => {
return Promise.reject(error)
}
)
Vue.prototype.$axios = axios;//把axios挂载到vue上
第五步
**
* 创建一个 token 拦截器.
* 需要继承 HandlerInterceptorAdapter,并且声明为spring的组件
*/
@Slf4j
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisUtil redisUtil;
// 重写 前置拦截方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("token");
if (StringUtils.isBlank(token)) {
throw new BusinessException(ResponseEnum.NOT_LOGGED_IN);
}
log.info("获取请求头中得token==>{}", token);
if (redisUtil.ttl(token) < 0) {
throw new BusinessException(ResponseEnum.LOGIN_SESSION_ERROR);
}
return true;
}
}
=====================================================
/**
* 设置拦截器.
* 打上configuration 注解,标注为配置项
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// 注入 token 拦截器
@Autowired
private TokenInterceptor interceptor;
/**
* 重写添加拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加自定义拦截器,并拦截对应 url
registry.addInterceptor(interceptor).addPathPatterns("/move2/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
.excludePathPatterns("/move/api/login/**")
.excludePathPatterns("/move/api/user/forget/**")
.excludePathPatterns("/move/api/group/**")
.excludePathPatterns("/move/api/project/**")
.excludePathPatterns("/move/api/user/register/**");
}
}
可能会出现跨域问题,帮你解决:
/**
* 跨域配置
*/
@Configuration
public class CorsConfig {
// 设置允许跨域的源
private static String[] originsVal = new String[]{
"192.168.10.44:8080",
"192.168.10.35:8080",
"192.168.10.41:8080"
};
/**
* 跨域过滤器
*
* @return
*/
@Configuration
public class CorsConfig {
// 设置允许跨域的源
private static String[] originsVal = new String[]{
"前端项目的ip地址",
"前端项目的ip地址",
"前端项目的ip地址"
};
/**
* 跨域过滤器
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
this.addAllowedOrigins(corsConfiguration);
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setMaxAge(3600L); // 这可以理解为一个缓存时间,在这个时间内如果是同一个ip过来的话就不用每次都发送跨域与请求,只是第一次发送跨域预请求(如果你发现这个没用的话,请你不要勾选浏览器的开发者工具中的Network中的Disable cache选项)
source.registerCorsConfiguration("/**", corsConfiguration); // 拦截解决跨域的地址
return new CorsFilter(source);
}
private void addAllowedOrigins(CorsConfiguration corsConfiguration) {
for (String origin : originsVal) {
corsConfiguration.addAllowedOrigin("http://" + origin);
corsConfiguration.addAllowedOrigin("https://" + origin);
}
}
}