註解攔截器權限控制

  • 註解類
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等第三方框架來實現權限的控制

 

 

 

 

 

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