• 让我们认识注解

    springboot实现权限控制可以使用shiro,是的springboot可以帮我们完成很多的事情,其实这篇文章的重点是注解,但是单独的说注解没什么意思,每样技术,我更关心的是它能做什么,我们为什么需要它,那么注解是我们需要的么?我想,它确实是被需要的,因为在自己写项目的时候会用到很多的注解比如说@RequestMapping、@Override,所以我觉的我需要了解一下它。

    • 注解是什么?

    我们先不说注解具体的定义是什么?我们先打个比方,说一下注解像什么,我的理解啊!注解像个便利贴,@Override是个便利贴,这个便利贴,提醒我在编译的时候检查是不是实现的是接口中的方法,有了这个注解,这个类本身的活动并没有发生改变,这个类是个处理servlet的类,加了注解后他还是这个功能,没有变,但是他影响了别人,这个别人可以看做是编译这件事情,编译的时候编译器看到了这个注解。

    • 为什么我们需要注解?

    有没有发现注解和一个东西很像,xml配置文件,我们在使用springMVC这个框架的时候,常常会用到这样的一个注解@RequestMapping,这个组件有一个value属性,用于记录路由信息,如果我们不适用springMVC这样的框架,如何实现一个servlet呢?可以参考下servlet 是什么 ,你会发现这里的这里的路由是通过XML来配置的,使用这种方式会有一些问题,比每次添加一个servlet都需要在XML文件当中配置一下,而如果使用注解,则只需要在controller处理方法的注解中添加一下,这里我们需要一个强耦合的配置方式。至于springMVC的@RequestMapping的实现方式可以参考下文档【7】。

    • 实现基于注解的权限控制

    创建权限注解

    1. package com.deepwater.daisy.annocation;
    2. import java.lang.annotation.*;
    3. // 该注解作用于方法
    4. @Target(ElementType.METHOD)
    5. // 该注解在代码运行时也是存在的
    6. @Retention(RetentionPolicy.RUNTIME)
    7. @Documented
    8. public @interface Access {
    9. String[] value() default {};
    10. String[] authorities() default {};
    11. String[] roles() default {};
    12. }
    13. 创建一个controller
    14. @RequestMapping(value = "/admin")
    15. // 通过注解配置该handler只能被拥有admin权限的人调用
    16. @Access(authorities = {"admin"})
    17. public String hello() {
    18. return "Hello, admin";
    19. }

    创建一个拦截器,用于在调用controller之前判断权限信息:

    1. package com.deepwater.daisy.interceptor;
    2. import com.deepwater.daisy.annocation.Access;
    3. import org.springframework.util.StringUtils;
    4. import org.springframework.web.method.HandlerMethod;
    5. import org.springframework.web.servlet.HandlerInterceptor ;
    6. import org.springframework.web.servlet.ModelAndView;
    7. import javax.servlet.http.*;
    8. import java.lang.reflect.Method;
    9. import java.util.HashSet;
    10. import java.util.Set;
    11. /**
    12. * @author jcxu
    13. * @date 20171012
    14. * @description 定义了一个拦截器
    15. */
    16. public class UserInterceptor implements HandlerInterceptor {
    17. public UserInterceptor() {
    18. super();
    19. }
    20. @Override
    21. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    22. System.out.println("请求开始被执行!");
    23. // 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
    24. HandlerMethod handlerMethod = (HandlerMethod) handler;
    25. // 从方法处理器中获取出要调用的方法
    26. Method method = handlerMethod.getMethod();
    27. // 获取出方法上的Access注解
    28. Access access = method.getAnnotation(Access.class);
    29. if (access == null) {
    30. // 如果注解为null, 说明不需要拦截, 直接放过
    31. return true;
    32. }
    33. if (access.authorities().length > 0) {
    34. // 如果权限配置不为空, 则取出配置值
    35. String[] authorities = access.authorities();
    36. Set<String> authSet = new HashSet<>();
    37. for (String authority : authorities) {
    38. // 将权限加入一个set集合中
    39. authSet.add(authority);
    40. }
    41. // 这里我为了方便是直接参数传入权限, 在实际操作中应该是从参数中获取用户Id
    42. // 到数据库权限表中查询用户拥有的权限集合, 与set集合中的权限进行对比完成权限校验
    43. String role = request.getParameter("role");
    44. if (!role.isEmpty()) {
    45. if (authSet.contains(role)) {
    46. // 校验通过返回true, 否则拦截请求
    47. return true;
    48. }
    49. }
    50. }
    51. // 拦截之后应该返回公共结果, 这里没做处理
    52. return false;
    53. }
    54. @Override
    55. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    56. System.out.println("请求正在被执行!");
    57. }
    58. @Override
    59. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    60. System.out.println("请求被执行完成!");
    61. }
    62. }


    注册该拦截器:

    1. package com.deepwater.daisy.configuration;
    2. import com.deepwater.daisy.interceptor.UserInterceptor;
    3. import org.springframework.context.annotation.Configuration;
    4. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    5. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    6. @Configuration
    7. public class InterceptorConfig extends WebMvcConfigurerAdapter {
    8. @Override
    9. public void addInterceptors(InterceptorRegistry registry) {
    10. //这里会对"/admin"的请求进行拦截
    11. registry.addInterceptor(new UserInterceptor()).addPathPatterns("/admin");
    12. }
    13. }


    我们可以看到没有请求会交个一个handler来处理,这个handler是谁呢!他就是我们用@RequestMapping注解的方法啊!我们会通过反射,找到注解对象的属性,获取到的属性,就像是获取到了该handler的标签,我们知道了这些handler的权限信息,注解对于其作用的包、类、方法并没有产生影响,但是在拦截器中,通过判断注解信息,实现了不同的操作。