拦截器的用处
譬如我们有一个页面/user/service,必须要登陆之后才能访问,这时候就需要token和拦截器了。
基本过程是这样的:首次登陆,后端不仅返回登陆成功信号,而且返回一个临时的token(String)。之后再进入任何一个页面需要带上这个token,如果token没有传入或者已经过期,则会被退回到登陆页面。
拦截器的实现
1.在Config包下新建一个MyInterceptor实现HandlerInterceptor并且重写preHandle方法。
@Configuration
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
}
第一个参数request用于获得url以及其他信息。
想要获得token只要在其中添加:
String token=request.getParameterValues("token")[0];
然后处理以下逻辑:
- 判断token是否存在,若不存在,返回false。
- 判断是否有token对应的用户,若不存在,返回false。
- 判断token是否过期,若过期返回false。
- 返回true。
第二个参数用于重定向。
response.sendRedirect("/user/error");
执行这条语句将意味着直接跳转到这个指定的url。
完成后的代码:
@Configuration
public class MyInterceptor implements HandlerInterceptor {
@Autowired
IndexService indexService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String[] tokens=request.getParameterValues("token");
if (tokens==null) {
response.sendRedirect("/user/error");
return false;
}
String token=tokens[0];
if (indexService.findByToken(token)==false){
response.sendRedirect("/user/error");
return false;
}
if (indexService.findExpiredTimeByToken(token).before(new Date())){
response.sendRedirect("/user/error");
return false;
}
return true;
}
}
2. 将MyInterceptor类在自己的配置类MyMvcConfig中进行注册。
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Autowired
MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePaths=new ArrayList<>();
excludePaths.add("/user/login/**");
excludePaths.add("/user/error");
registry.addInterceptor(myInterceptor).addPathPatterns("/user/**").excludePathPatterns(excludePaths);
//参数可以是单个路径的字符串,也可以是多个路径的list
}
}
3.Controller
在登陆的逻辑中,只需要添加token的生成、token以及过期时间的存储即可。返回当然要返回生成的token。
@RestController
@RequestMapping("/user")
public class IndexController {
@Autowired
IndexService indexService;
@GetMapping("/login/{user}")
public String login(@PathVariable int user){
return indexService.login(user);
}
@GetMapping("/service")
public String service(){
return "token right";
}
@GetMapping("/error")
public String error(){
return "error";
}
}
4.Service
@Service
public class IndexService {
Map<String,Integer> map= new HashMap<>();
Map<String, Date> map2=new HashMap<>();
public Boolean findByToken(String token){
if (map.get(token)==null) return false;else return true;
}
public Date findExpiredTimeByToken(String token){
return map2.get(token);
}
public String login(Integer user){
String token= UUID.randomUUID().toString();
map.put(token,user);
map2.put(token,new Date(System.currentTimeMillis()+60*1000));
return token;
}
}
这里用两个map模拟了数据库,当登陆成功的时候,map将自动生成token,并存储token、过期时间、用户id。过期时间暂定为1分钟。
测试
我们先打开/user/service,请求直接跳转到service界面,发现被拦截器返回到/user/error界面。
然后我们打开/user/login/1,进行用户1的登陆,服务端返回token:69cd3539-6069-43d6-9744-073778bc6e99
然后我们访问/user/service?token=69cd3539-6069-43d6-9744-073778bc6e99,访问成功。
过了一分钟再访问一样的界面,返回到/user/error界面。