如何通过拦截器完成权限控制
拦截器
概念
java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action
执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截
然后再之前或者之后加入某些操作。
实现方式
- 第一步 定义注解
package com.alibaba.gov.kamala2.service.annotation;
import com.alibaba.gov.kamala2.enums.userrole.Kamala2LevelEnum;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AclUrlAutoHandle {
/**
* 权限名称
* @return
*/
String name();
/**
* 默认值 暂无意义
* @return
*/
String value() default "";
/**
* 唯一码
* @return
*/
String code();
/**
* 优先级
* @return
*/
Kamala2LevelEnum level() default Kamala2LevelEnum.LOW;
/**
* 是否需要校验node权限
* @return
*/
boolean nodeFlg() default false;
/**
* 描述
* @return
*/
String description() default "系统添加的权限";
}
- 第二步 定义拦截器类,该类实现HandlerInterceptor接口,并重写preHandle、postHandle、afterCompletion方法(如有需要);此处只需要重写preHandler即可;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
//注入上下文
@Autowired
private ApplicationContext applicationContext;
/**
* 该方法是在执行执行servlet的 service方法之前执行的
* 即在进入controller之前调用
* @return 如果返回true表示继续执行下一个拦截器的PreHandle方法;如果没有拦截器了,则执行controller
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
RequestMappingHandlerMapping rmhp = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = rmhp.getHandlerMethods();
for(RequestMappingInfo info : map.keySet()){
HandlerMethod hm=map.get(info);
Method method = hm.getMethod();
Object o = method.getAnnotation(AclUrlAutoHandle.class);
if(o!= null){
System.out.println(info.getPatternsCondition());
}
}
return true;
}
/**
*在执行完controller之后,返回视图之前执行,我们可以对controller返回的结果做处理
* 执行顺序:先执行最后一个拦截器的postHandle方法,一次向前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception{
System.out.println("解析视图之前.....");
}
/**
* 整个请求结束之后,即返回视图之后执行
*该方法需要同一拦截器的preHandle返回true时执行,
* 如果该拦截器preHandle返回false,则该拦截器的afterCompletion不执行
* 执行顺序:先执行最后一个返回true的拦截器的afterCompletion,在依次向前
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception{
System.out.println("视图解析完成...");
}
}
- 第三步:重写preHandler方法,在该方法体中获取含有自定义注解的url,并保存到set中;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
RequestMappingHandlerMapping rmhp = applicationContext.getBean(RequestMappingHandlerMapping.class);
Set<String> set = new HashSet<>();
Map<RequestMappingInfo, HandlerMethod> map = rmhp.getHandlerMethods();
for(RequestMappingInfo info : map.keySet()){
HandlerMethod hm=map.get(info);
Method method = hm.getMethod();
Object o = method.getAnnotation(AclUrlAutoHandle.class);
if(o!= null){
System.out.println(info.getPatternsCondition());
set.add(info.getPatternsCondition().toString());
}
}
return true;
}
- 根据用户、角色、权限、授权记录四张表中的逻辑关系,来确定该用户是否有某一路径的权限(此处不做详细展开)