1-2 分布式session(二)
问题:
用户第一次登录之后会得到一个cookie,在以后每次的访问过程中都会携带这个cookie,后台所有的需要登录权限的controller都要先获取cookie中的token,再使用token从session中获取用户登录信息来完成用户身份认证,所以所有的controller中都加上身份认证的代码非常冗余,因此需要把相同的代码抽取出来。
解决:
Spring Boot中的WebMvcConfigurer(前身是WebMvcConfigurerAdapter)接口提供了很多的方法对网站进行个性化定制,例如配置拦截器、配置ViewController、配置Cors跨域等。其中,addArgumentResolvers()方法可以用在对于Controller中方法参数传入之前对该参数进行处理,然后将处理好的参数再传给Controller中的方法。所以身份认证可以放在这个方法中完成。这个方法只有一个参数:argumentResolvers,它存储了所有的参数解析器,自定义参数解析器后通过调用add()方法加入参数解析器列表。
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add();
}
argumentResolver参数解析器原理
自定义参数解析器必须实现HandlerMethodArgumentResolver接口,supportsParameter()方法用于判断该参数是否使用该解析器,resolveArgument()方法是解析器的具体解析操作,所以整体逻辑就是框架会将每一个MethodParameter传入supportsParameter判断是否需要被处理,如果需要,就使用resolveArgument进行处理。public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
自定义cookie解析器
定义UserArgumentResolver类实现HandlerMethodArgumentResolver接口,首先判断参数是不是MiaoshaUser类型,如果是就进行token校验。package com.imooc.miaosha.config;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import com.imooc.miaosha.domain.MiaoshaUser;
import com.imooc.miaosha.service.MiaoshaUserService;
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
MiaoshaUserService userService;
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz = parameter.getParameterType();
return clazz==MiaoshaUser.class;
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return null;
}
String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
return userService.getByToken(response, token);
}
private String getCookieValue(HttpServletRequest request, String cookiName) {
Cookie[] cookies = request.getCookies();
for(Cookie cookie : cookies) {
if(cookie.getName().equals(cookiName)) {
return cookie.getValue();
}
}
return null;
}
}
定义WebConfig类实现WebMvcConfigurer,然后将定义的参数解析器userArgumentResolver添加到参数解析器列表中。
package com.miaosha.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
public class WebConfig implements WebMvcConfigurer {
@Autowired
UserArgumentResolver userArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
}
}
然后controller方法就比较干净简洁啦!
@RequestMapping("/to_list")
public String list(Model model,MiaoshaUser user) {
model.addAttribute("user", user);
return "goods_list";
}

浙公网安备 33010602011771号