- 让我们认识注解
springboot实现权限控制可以使用shiro,是的springboot可以帮我们完成很多的事情,其实这篇文章的重点是注解,但是单独的说注解没什么意思,每样技术,我更关心的是它能做什么,我们为什么需要它,那么注解是我们需要的么?我想,它确实是被需要的,因为在自己写项目的时候会用到很多的注解比如说@RequestMapping、@Override,所以我觉的我需要了解一下它。
- 注解是什么?
我们先不说注解具体的定义是什么?我们先打个比方,说一下注解像什么,我的理解啊!注解像个便利贴,@Override是个便利贴,这个便利贴,提醒我在编译的时候检查是不是实现的是接口中的方法,有了这个注解,这个类本身的活动并没有发生改变,这个类是个处理servlet的类,加了注解后他还是这个功能,没有变,但是他影响了别人,这个别人可以看做是编译这件事情,编译的时候编译器看到了这个注解。
- 为什么我们需要注解?
有没有发现注解和一个东西很像,xml配置文件,我们在使用springMVC这个框架的时候,常常会用到这样的一个注解@RequestMapping,这个组件有一个value属性,用于记录路由信息,如果我们不适用springMVC这样的框架,如何实现一个servlet呢?可以参考下servlet 是什么 ,你会发现这里的这里的路由是通过XML来配置的,使用这种方式会有一些问题,比每次添加一个servlet都需要在XML文件当中配置一下,而如果使用注解,则只需要在controller处理方法的注解中添加一下,这里我们需要一个强耦合的配置方式。至于springMVC的@RequestMapping的实现方式可以参考下文档【7】。
- 实现基于注解的权限控制
创建权限注解
package com.deepwater.daisy.annocation;import java.lang.annotation.*;// 该注解作用于方法@Target(ElementType.METHOD)// 该注解在代码运行时也是存在的@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Access {String[] value() default {};String[] authorities() default {};String[] roles() default {};}创建一个controller:@RequestMapping(value = "/admin")// 通过注解配置该handler只能被拥有admin权限的人调用@Access(authorities = {"admin"})public String hello() {return "Hello, admin";}
创建一个拦截器,用于在调用controller之前判断权限信息:
package com.deepwater.daisy.interceptor;import com.deepwater.daisy.annocation.Access;import org.springframework.util.StringUtils;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor ;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.*;import java.lang.reflect.Method;import java.util.HashSet;import java.util.Set;/*** @author jcxu* @date 20171012* @description 定义了一个拦截器*/public class UserInterceptor implements HandlerInterceptor {public UserInterceptor() {super();}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("请求开始被执行!");// 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethodHandlerMethod handlerMethod = (HandlerMethod) handler;// 从方法处理器中获取出要调用的方法Method method = handlerMethod.getMethod();// 获取出方法上的Access注解Access access = method.getAnnotation(Access.class);if (access == null) {// 如果注解为null, 说明不需要拦截, 直接放过return true;}if (access.authorities().length > 0) {// 如果权限配置不为空, 则取出配置值String[] authorities = access.authorities();Set<String> authSet = new HashSet<>();for (String authority : authorities) {// 将权限加入一个set集合中authSet.add(authority);}// 这里我为了方便是直接参数传入权限, 在实际操作中应该是从参数中获取用户Id// 到数据库权限表中查询用户拥有的权限集合, 与set集合中的权限进行对比完成权限校验String role = request.getParameter("role");if (!role.isEmpty()) {if (authSet.contains(role)) {// 校验通过返回true, 否则拦截请求return true;}}}// 拦截之后应该返回公共结果, 这里没做处理return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("请求正在被执行!");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("请求被执行完成!");}}
注册该拦截器:
package com.deepwater.daisy.configuration;import com.deepwater.daisy.interceptor.UserInterceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configurationpublic class InterceptorConfig extends WebMvcConfigurerAdapter {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//这里会对"/admin"的请求进行拦截registry.addInterceptor(new UserInterceptor()).addPathPatterns("/admin");}}
我们可以看到没有请求会交个一个handler来处理,这个handler是谁呢!他就是我们用@RequestMapping注解的方法啊!我们会通过反射,找到注解对象的属性,获取到的属性,就像是获取到了该handler的标签,我们知道了这些handler的权限信息,注解对于其作用的包、类、方法并没有产生影响,但是在拦截器中,通过判断注解信息,实现了不同的操作。
