注解拦截器权限控制

  • 注解类
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 权限校验注解,加入之后判断是否有权限访问方法
 *
 * @author czs
 * @date 2020-4-20 19:40:10
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PurviewValid
{
    /**
     * 本方法权限码
     */
    int purviewId();
}
  • 注解类的拦截器

import com.alibaba.fastjson.JSON;
import com.uindata.common.pojo.CommonResponse;
import com.uindata.entity.sb.TSbPurview;
import com.uindata.util.Constants;
import com.uindata.util.FastJsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * 权限校验拦截器,检查请求的方法上是否有权限注解,拿到注解内的参数值对比该用户在session内的权限集合来辨别是否有权限
 */
@Slf4j
public class PurviewValidInterceptor extends HandlerInterceptorAdapter
{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        try
        {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");

            Method method = ((HandlerMethod) handler).getMethod();
            if (AnnotatedElementUtils.isAnnotated(method, PurviewValid.class))
            {
                final HttpSession session = request.getSession();
                Object userInfo = session.getAttribute(Constants.CACHE_REDIS_KEY.USER_INFO);
                final String userStr = userInfo.toString();
                int purviewId = method.getDeclaredAnnotation(PurviewValid.class).purviewId();
                // 获得用户存储在redis中的权限
                Object purviewObj = session.getAttribute(Constants.CACHE_REDIS_KEY.USER_PURVIEW);

                if (null == purviewObj)
                {
                    response.getWriter().print(FastJsonUtils.obj2JsonStr(CommonResponse.failed("获取权限列表失败!")));
                    final String msg = "用户 " + userStr + " 获取权限列表失败!";
                    log.error(msg);
                    return false;
                }
                final List<TSbPurview> province = JSON.parseArray(purviewObj.toString(), TSbPurview.class);
                if (0 == province.size())
                {
                    response.getWriter().print(FastJsonUtils.obj2JsonStr(CommonResponse.failed("权限校验失败!")));
                    final String msg = "用户 " + userStr + " 权限校验失败!";
                    log.warn(msg);
                    return false;
                }
                final List<Integer> provinceIds = Arrays.asList(province.stream()
                        .map(TSbPurview::getId)
                        .toArray(Integer[]::new));
                if (!provinceIds.contains(new Integer(purviewId)))
                {
                    response.getWriter().print(FastJsonUtils.obj2JsonStr(CommonResponse.failed("权限校验失败!")));
                    final String msg = "用户 " + userStr + " 权限校验失败!";
                    log.warn(msg);
                    return false;
                }
            }
        }
        catch (Exception e)
        {
            log.error("权限校验失败!", e);
            response.getWriter().print(FastJsonUtils.obj2JsonStr(CommonResponse.failed("权限校验失败!")));
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
    {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
    {
    }

}
  • WebConfigurer应用拦截器

import com.uindata.conf.purview.PurviewValidInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @Description: 配置web
 * 必须配置在一个类下
 * @auther: 
 * @date: 11:51 2020/4/8
 * @param:
 * @return:
 */
@Configuration
@EnableSwagger2
@ConditionalOnProperty(prefix = "mconfig", name = "swagger-ui-open", havingValue = "true")
public class WebConfigurer extends WebMvcConfigurationSupport
{

    /**
     * 权限验证bean
     *
     * @return
     */
    @Bean
    public PurviewValidInterceptor getPurviewValidInterceptor()
    {
        return new PurviewValidInterceptor();
    }

    /**
     * @Description: 配置拦截器 -> 所有以xxx开头的访问都进入RedisSessionInterceptor拦截器进行登录验证,并排除/xxx/yyy接口
     * 注意:
     * 必须写成链式,分别设置的话会创建多个拦截器
     * 必须写成getSessionInterceptor(),否则SessionInterceptor中的@Autowired会无效
     * @auther: xiaoyi
     * @date: 10:11 2020/4/8
     * @param: [registry]
     * @return: void
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        // 权限校验注解,拦截所有
        registry.addInterceptor(getPurviewValidInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")     // 排除swagger
        ;
        super.addInterceptors(registry);
    }

}
  • 使用
    /**
     * 删除角色
     *
     * @param roleId
     * @return
     */
    @DeleteMapping("deleteRole")
    @ApiOperation(value = "删除角色")
    @ApiImplicitParam(name = "roleId", value = "角色id", required = true, paramType = "query", dataType = "int")
    @PurviewValid(purviewId = 50203)
    public CommonResponse deleteRole(Integer roleId)
    {
        if (Objects.isNull(roleId))
        {
            return CommonResponse.failed("ID不能为空!");
        }
        TSbRole tSbRole = tSbRoleService.getById(roleId);
        if (Objects.isNull(tSbRole))
        {
            return CommonResponse.failed("ID不正确!");
        }
        tSbRoleService.removeRole(roleId);
        return CommonResponse.ok("删除成功!");
    }

 

结语:本次的权限码被存储在了数据库,数据库中包含了用户、角色、菜单、用户角色关联、角色菜单关联等构成权限的基础表,再通过管理员的web界面去给用户授予角色、给角色授予权限,最终实现了简化版的权限控制,但这里更多的提供的是注解拦截器的一个基本思路,还是建议使用Security等第三方框架来实现权限的控制

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章