SpringBoot分布式session以及自定义拦截器注解

分布式session

思路:
(1)用户登录

  • 失败:返回错误信息
  • 成功:生成随机字符串token(uuid),用户信息存入redis中

(2)获取用户
cookie中获取token,再从redis中获取用户对应信息

  • 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {
    private Integer id;
    private String username;
    private String password;
    // 1 为管理员用户
    // 2 为普通用户
    private Integer userType;
}
  • 用hashmap模拟redis
public class CacheUtil {
    public static Map<String, User> userCache = new HashMap<>();
}
  • 接收用户登录VO类
@Data
public class LoginVO {
    private String username;
    private String password;
}
  • controller
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/login")
    public String login(LoginVO loginVO, HttpServletResponse response) {

        return userService.login(loginVO, response);
    }
    // 1 管理员
    // 2. 普通用户

    // 判断用户类型 开始的版本 每次需要获取用户信息都得这样判断,太重复了
    @GetMapping("/index")
    public String index(@CookieValue("token")Cookie cookie) {
    	// 从cookie中获取token对应的值,再到‘redis‘中获取用户
        String value = cookie.getValue();
        User user = CacheUtil.userCache.get(value);
        if (user.getUserType() != 1) {
            return "你是普通用户,权限不足";
        }
        return user.toString();
    }

    @GetMapping("/index2")
    public String index(User user) {
        if (user.getUserType() != 1) {
            return "你是普通用户,权限不足";
        }
        return user.toString();
    }

    @GetMapping("/index3")
    @AccessLimit //自定义的拦截器注解
    public String index3(User user ) {

        return "limit 验证管理员通过" + user.toString();
    }

}
  • UserService
@Service
public class UserService{

    public static Set<User> dbUser = new HashSet<>();

    // 模拟数据库用户
    static {
        dbUser.add(new User().setId(1).setUsername("admin").setPassword("admin").setUserType(1));
        dbUser.add(new User().setId(2).setUsername("user").setPassword("user").setUserType(2));
        dbUser.add(new User().setId(3).setUsername("zhangsan").setPassword("123456").setUserType(2));
    }
    public String login(LoginVO loginVO, HttpServletResponse response) {
        Optional<User> userOptional = dbUser.stream().filter(u -> u.getUsername().equals(loginVO.getUsername())
                && u.getPassword().equals(loginVO.getPassword())).findFirst();

        if (userOptional.isPresent()) {
            User user = userOptional.get();
            //验证通过生成token
            String token = UUID.randomUUID().toString();

            Cookie cookie = new Cookie("token",token);
            cookie.setPath("/");
            //用户信息存入缓存中  模拟
            CacheUtil.userCache.put(token,user);

            response.addCookie(cookie);
            return "登录成功:" + user.toString();
        } else {
            return "用户名或者密码错误";
        }
    }
    //从request中获取cookie中对应的用户信息
    public static String getCookieValue(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length <= 0) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("token")) {
                return cookie.getValue();
            }
        }
        return null;
    }
}

像上面的/index1,只要一需要用户信息,都需要从cookie中,再从redis中获取信息,太繁琐了,所以让我们自定义一个参数解析器,直接获取用户信息

  • 自定义UserArgumentResolver
@Configuration
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        Class<?> clazz = methodParameter.getParameterType();
        // 只要controller中使用User作为参数(像/index2,/index3那样),就执行
        return clazz == User.class;
    }
    // 把之前的验证拿到这来
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response = nativeWebRequest.getNativeRequest(HttpServletResponse.class);
        // 获取 cookie
        String cookieValue = UserService.getCookieValue(request);
        if (cookieValue != null) {
            User user = CacheUtil.userCache.get(cookieValue);
            return user;
        }
        return null;
    }
}
  • UserArgumentResolver添加到 WebMvcConfigurer方法里面
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private UserArgumentResolver userArgumentResolver;

//    @Autowired
//  private AccessInterceptor accessInterceptor;
    //参数
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userArgumentResolver);
    }
    //自定义拦截器注解  后面用到的
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(accessInterceptor);
//    }
}

这样就像上面/index2添加User参数获取对应信息了
如:

@GetMapping("/index2")
public String index(User user) {
    if (user.getUserType() != 1) {
        return "你是普通用户,权限不足";
    }
    return user.toString();
}

自定义拦截器注解

但我有些接口只能让管理员(userType=1)才能访问呢
不可能每次都自己手写重复代码

  if (user.getUserType() != 1) {
        return "你是普通用户,权限不足";
    }

这样也太麻烦了吧,所以我们用到了自定义拦截器注解

  • 定义注解AccessLimit
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    int type() default 2;//默认是普通用户 其实没有用到
}
  • 定义拦截器AccessInterceptor
@Configuration
public class AccessInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        response.setContentType("text/html;charset=UTF-8");
        if(handler instanceof HandlerMethod){

            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
				
			// 如果没有使用  accessLimit 就直接放行
            if(accessLimit==null){
                return true;
            }
            String cookieValue = UserService.getCookieValue(request);

            if(cookieValue==null){
                response.getWriter().write("please login");
                return false;
            }
            User user = CacheUtil.userCache.get(cookieValue);
            if(user.getUserType()!=1){
                response.getWriter().write("只有管理员才能访问!!!");
                return false;
            }
        }
        return true;
    }
}
  • 添加到WebConfig

其实打开 WebConfig里面注释的代码即可

   @Autowired
   private AccessInterceptor accessInterceptor;

	//自定义拦截器注解
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
	    registry.addInterceptor(accessInterceptor);
	}

这下就添加一个注解@AccessLimit即可判断userType是否满足条件了
如:

    @GetMapping("/index3")
    @AccessLimit
    public String index3(User user ) {

        return "limit 验证管理员通过" + user.toString();
    }
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页