基于拦截器的后端资源权限实现

发布于:2022-12-13 ⋅ 阅读:(177) ⋅ 点赞:(0)

背景

权限实现是web应用项目永远绕不开的话题,诸如SpringSecurity、Shiro等安全框架也提供了相对健全的解决方案。但如果摒弃这些框架单从功能实现出发实现多账户多角色的权限分管其实思路也很简单。

思路分析

后端实现(接口资源管理)

针对后端开发,基于springboot,我们可以采用拦截器与自定义注解配合实现 面向用户的 后台接口资源的管理。在用户登录时,将该账户可用的接口资源路径以某种形式存放在缓存中,当接口请求发起时,拦截器解析该账户所拥有的接口资源路径并与请求体路径相比对。这样,只需管理好用户与后台接口资源路径的对应关系在一定意义上就实现了针对用户的能力(即后台权限)的管理。

当然,针对后台接口资源实现面向用户的分管并不是非拦截器不可,同样的道理,我们采用AOP或过滤器实现 理论上也是可行的,总体思路都是在请求访问时做鉴权回应。后面我们会着重针对拦截器实现和AOP实现 两种实现方式做代码分析。

在这里插入图片描述

前端实现(组件资源可见/可操作)

针对前端开发,思路上可以通过解析用户的权限资源(这里要求后端有权限相关的库表设计)来对前端组件的可见性/可操作性进行管控。这部分不是本篇论述的重点,点到为止,不做赘述。

基于拦截器实现后端资源权限管理

以下代码在springboot中实现。用户登录的信息(授权接口资源等)缓存(session或自定义cookie)的编写这里不做介绍,各位可以按自己的思路实现,只要能够在请求体中解析即可。

1. 配置拦截器

import cn.wayne.util.ReqInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private ReqInterceptor reqInterceptor;
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {}
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //在 WebConfigurer 中的 addInterceptors 中添加拦截,放行
        // addPathPatterns("/**") 表示拦截所有的请求,
        // excludePathPatterns("/login", "/register") 表示对登录注册放行
        registry.addInterceptor(reqInterceptor).addPathPatterns("/**").excludePathPatterns("/login", "/register");
    }
}

2. 自定义注解–鉴权开关

这个注解主要是我为了轻便的管理哪些接口需要鉴权。在实际的开发应用中,并不是所有的接口都要做权限管理。当然各位可以按照自己的思路去做优化。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义权限注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RightAnno {
    public boolean value() default true;     //true表示被标注的方法参与后台资源管控
}

3. 编写拦截器

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截器
 */
@Component
@Slf4j
public class ReqInterceptor implements HandlerInterceptor {

    @Autowired
    private LoginUserUtil loginUserUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("进入拦截器");
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        //1.获取目标类上的目标注解(可判断目标类是否存在该注解)
        RequestMapping reqMappingClass = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), RequestMapping.class);
        //2.获取目标方法上的目标注解(可判断目标方法是否存在该注解)
        RequestMapping reqMappingMethod = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), RequestMapping.class);
        RightAnno rightAnno = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), RightAnno.class);
        //判断请求上是否有自定义注解且注解值为true,如过是,开启鉴权
        if (rightAnno!=null&&rightAnno.value()){
//            BiUser loginUser = loginUserUtil.getBiUserByCookie(request);
//            Integer hrId = loginUser.getHrId();//请求人hrid
//            log.info(hrId.toString());
            log.info("批准执行拦截");
            log.info("reqClass=="+reqMappingClass);
            log.info("reqMethod=="+reqMappingMethod);
            log.info("inMethod=="+rightAnno);
            log.info("thePath=="+reqMappingClass.value()[0]+reqMappingMethod.value()[0]);
            //这里编写解析你的用户资源,根据条件控制返回值,返回false则请求被拦截       

            return true;
        }
        return true;
    }
}

4. controller实例

@RequestMapping("/listHighRightCountViewInfo.do")
    @ResponseBody
    @RightAnno
    public ResponseResult<JSONObject> listHighRightCountViewInfo(@RequestBody JSONObject inJson, HttpServletRequest request){
    
}

基于AOP实现后端资源权限管理

1. 自定义注解及controller实现

与上文相同,不做赘述。

2. 编写AOP

@Before(value = "execution(* com.wayne.controller.*.*(..)) " +
            "&& !execution(* com.wayne.controller.testController.*(..))")
    public void before(JoinPoint joinPoint){
        ResponseResult<Void> rr = null;
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        HttpServletResponse response =sra.getResponse();
        //获得目标方法的签名对象
                Signature signature = joinPoint.getSignature();
                //将目标方法的签名对象转化为MethodSignature
                MethodSignature methodSignature= (MethodSignature) signature;
                //获得方法的注解
                Method method = methodSignature.getMethod();
                Object target = joinPoint.getTarget();
                Method realMethod = (Method) target .getClass().getDeclaredMethod(signature.getName(),method.getParameterTypes());
                RightAnno annotation = realMethod.getAnnotation(RightAnno.class);
        //判断请求上是否有自定义注解且注解值为true,如过是,开启鉴权
        if (rightAnno!=null&&rightAnno.value()){
            //这里编写解析你的用户资源,若权限不足抛出RuntimeException打断请求

        }
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到