美文网首页
基于HandlerInterceptor权限统一拦截

基于HandlerInterceptor权限统一拦截

作者: 离别刀 | 来源:发表于2018-05-25 10:21 被阅读0次
80608151328.png

HandlerInterceptor基于JDK动态代理实现request的拦截。接口共有3个方法:

public interface HandlerInterceptor {
    boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
    void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}

1.preHandle,在访问真正的request之前的预处理,只有该方法返回true时候,请求才能到达controller。因此我们可以在此对request做一定处理。比如判断用户是否有权限访问该接口、对接口访问做日志记录等。

2.postHandle,只有当preHandle返回true之后,才能执行该接口,该接口是在请求完成之后,DispatcherServlet进行视图返回渲染之前调用。一般在此接口我们可以操作ModelAndView,在实际当中我们可以在此处设置静态文件的版本号,jsp中的静态文件引用只需要引用改变量,就可以实现动态刷新静态文件。

3.afterCompletion,该接口也是只有当preHandle返回true之后才会执行,它是在DispatcherServlet渲染完模板之后才会调用。一般在次方法中清除缓存变量等。比如我们想实现一个用户请求过来,验证完权限之后,我们在preHandle中将用户信息放到ThreadLocal中,后面的controller,service就直接可以从该接ThreadLocal中获取用户信息。但当该请求完成之后,需要在afterCompletion中清理该ThreadLocal变量。

下面示例主要是实现用户权限的拦截,比较简单,该示例中用到了自定义注解,对于controller中加了注解的接口,在拦截器可以根据注解设置不同的拦截;如下面设置了Permition注解 124100740.png

,表示该接口开放。

拦截器

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Value("${session.timeout}")
    private long EXPIRE_TIME;//用户session缓存时间
    @Autowired
    private RedisOperations redisOperations;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler == null || handler instanceof ResourceHttpRequestHandler) {
            return true;
        }
        if(handler instanceof HandlerMethod){
            String name= ((HandlerMethod) handler).getMethod().getName();
            if(("errorHtml".equalsIgnoreCase(name))){
                throw new PageException("the url: "+request.getRequestURL()+" not exists.");
            }
        }
        return verify(request,handler);
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        UserThreadLocal.clear();
    }

    private boolean verify(HttpServletRequest request, Object handler){
        Permition permition = verifyPermit(handler);
        if(permition!=null && permition.oriented()==Permit.All){
            return true;
        }
        return verifyUser(request);
    }

    private boolean verifyUser(HttpServletRequest request){
        //假设用户的身份信息是从header上传,从header中取出身份信息
        String headerKey= request.getHeader(UserKeyUtils.IDENTITY);
        if(StringUtils.isEmpty(headerKey)){
            throw new BusinessException(0,"no authority.");
        }
        //从身份信息中提取出用户key
        String userRedisKey= UserKeyUtils.getUserRedisKey(headerKey);
        //从缓存中获取用户信息
        User user= redisOperations.getVal(userRedisKey,User.class);
        if(user==null){
            throw new BusinessException(-1,"token invalidate or expired.");
        }
        if(StringUtils.isEmpty(user.schoolId)){
            throw new BusinessException("schoolId not empty.");
        }
        user.token = headerKey;
        //验证完成之后会将用户信息存入redis
        redisOperations.putVal(userRedisKey,user,EXPIRE_TIME);
        //用户信息存入ThreadLocal
        UserThreadLocal.set(user);
        return true;
    }
    
    //权限验证,可以在此处扩展更复杂的权限控制,比如基于url的资源拦截。
    private Permition verifyPermit(Object handler) {
        Permition permit= null;
        if (handler instanceof HandlerMethod){
             permit = ((HandlerMethod) handler).getMethod().getAnnotation(Permition.class);
            if(permit == null){
                permit = ((HandlerMethod) handler).getBeanType().getAnnotation(Permition.class);
            }
        }
        return permit;
    }
}

UserThreadLocal

public class UserThreadLocal {
    private static final ThreadLocal<User> userThreadLocal= new ThreadLocal<>();
    public static User get(){
       return userThreadLocal.get();
    }
    public static void set(User user){
        userThreadLocal.set(user);
    }
    public static void clear(){
        userThreadLocal.remove();
    }
}

相关文章

网友评论

      本文标题:基于HandlerInterceptor权限统一拦截

      本文链接:https://www.haomeiwen.com/subject/jllyjftx.html