如何实现session共享问题:
1、session都在内存里面存储的,只要有session对象我都分发出去,让其他应用都可以拿到(同步)
缺点:只要有session对象都要广播出去,而且用户应用比较多了就会导致服务压力大,
2、使用token,登录完之后给你一个token,然后加密完之后发给服务器,用的时候直接把token给带过来即可,别的应用调用的时候就会拿到token相应的信息,这样就解决了session共享问题。
Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。
在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,
定义一个拦截器可以通过两种方式:
代码编辑在interceptor包下创建
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法处理控制器(controller)方法调用之前");
String token=request.getParameter("token");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("preHandle方法处理控制器(controller)方法调用之后,在解析视图之前执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion在视图渲染之后执行");
}
}
配置类里面配置拦截器:
@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**");
}
对token进行验证判断:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法处理控制器(controller)方法调用之前");
String token=request.getParameter("token");
//对token进行判断
if(token !=null && token.equals("206")){
return true;
}
System.out.println("不是206学员");
return false;
}
访问测试:http://localhost:8080/gff/mother?token=206
如果被拦截了,是不是要给一个响应信息,或错误信息。
另外jwt里面也介绍说明:需要放到请求头里面
JWT跨域认证解决方案_赵同学&的博客-CSDN博客
运行测试:
除了返回状态码还可以指定放回格式:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法处理控制器(controller)方法调用之前");
//获取请求头 getheader
String token=request.getHeader("token");
if(token !=null && token.equals("206")){
return true;
}
System.out.println("不是正牌男友");
//错误状态码
// onse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
//指定返回格式
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"code\":401,\"message\":\"token必须传入\"}");
return false;
}
如果第一个拦截器出现问题了怎么办? 可以在添加一个:新创建一个SexInterceptor
public class SexInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法处理控制器(controller)方法调用之前");
String token=request.getParameter("sex");
if(token !=null && token.equals("girl")){
return true;
}
System.out.println("什么玩意");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
配置类配置:多拦截配置
@Override
public void addInterceptors(InterceptorRegistry registry) {
//order值越小越先执行
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new SexInterceptor()).addPathPatterns("/**");
}
使用order调整顺序: order值越小越先执行
@Override
public void addInterceptors(InterceptorRegistry registry) {
//order值越小越先执行
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**").order(2);
registry.addInterceptor(new SexInterceptor()).addPathPatterns("/**").order(1);
}
放行验证:创建一个controller:
@RestController
@RequestMapping("/glf")
public class GirlFriendController {
@GetMapping("/old")
public String select(){
return "这是你们前女友";
}
比如针对性拦截:api路径
@Override
public void addInterceptors(InterceptorRegistry registry) {
//order值越小越先执行
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/api/**").order(2);
}
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法在HandlerMethod执行之前");
//获取token
String token = request.getHeader("token");
//如果token不为空,进行token验证
if (token.equals("123456")) {
return true;
}
//没有token,直接返回401
// response.setStatus(401);
//或者
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"code\":401,\"message\":\"token必需传\"}");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle方法在HandlerMethod调用之后,解析视图之前执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion方法在视图渲染结束之后执行");
}
}
在上述拦截器的定义中实现了 HandlerInterceptor 接口,并实现了接口中的 3 个方法。有关这 3 个方法的描述如下。
preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。
@Configuration
//开启 Spring MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 可添加多个
// order 谁小谁先拦截
registry.addInterceptor(new TokenIntercepter()).addPathPatterns("/**").order(2);
registry.addInterceptor(new SexIntercepter()).addPathPatterns("/**").order(1);
}
/**
* 视图配置
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
WebMvcConfigurer.super.configureViewResolvers(registry);
registry.viewResolver(resourceViewResolver());
/*registry.jsp("/WEB-INF/jsp/",".jsp");*/
}
/**
* 配置请求视图映射
*/
private InternalResourceViewResolver resourceViewResolver()
{
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
//请求视图文件的前缀地址
internalResourceViewResolver.setPrefix("/WEB-INF/jsp/");
//请求视图文件的后缀
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
}