基于shiro的改造集成真正支持restful请求

本文介绍如何改造Shiro以真正支持RESTful请求,通过自定义过滤器链匹配URL并考虑HTTP方法,实现基于角色的权限访问控制。详细讲解了改造的核心代码和流程,并提供了项目的GitHub和码云链接。
摘要由CSDN通过智能技术生成

基于shiro的改造集成真正支持restful请求

这个模块分离至上上上一篇api权限管理系统与前后端分离实践,感觉那样太长了找不到重点,分离出来要好点。


首先说明设计的这个安全体系是是RBAC(基于角色的权限访问控制)授权模型,即用户--角色--资源,用户不直接和权限打交道,角色拥有资源,用户拥有这个角色就有权使用角色所用户的资源。所有这里没有权限一说,签发jwt里面也就只有用户所拥有的角色而没有权限。

为啥说是真正的restful风格集成,虽说shiro对rest不友好但他本身是有支持rest集成的filter–HttpMethodPermissionFilter,这个shiro rest的 风格拦截器,会自动根据请求方法构建权限字符串( GET=read,POST=create,PUT=update,DELETE=delete)构建权限字符串;eg: /users=rest[user] , 会 自动拼接出user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll)。

但是这样感觉不利于基于jwt的角色的权限控制,在细粒度上验权url(即支持get,post,delete鉴别)就更没法了(个人见解)。打个比方:我们对一个用户签发的jwt写入角色列(role_admin,role_customer)。对不同request请求:url="api/resource/",httpMethod="GET"url="api/resource",httpMethod="POST",在基于角色-资源的授权模型中,这两个url相同的请求对HttpMethodPermissionFilter是一种请求,用户对应的角色拥有的资源url=”api/resource”,只要请求的url是”api/resource”,不论它的请求方式是什么,都会判定通过这个请求,这在restful风格的api中肯定是不可取的,对同一资源有些角色可能只要查询的权限而没有修改增加的权限。

可能会说在jwt中再增加权限列就好了嘛,但是在基于用户-资源的授权模型中,虽然能判别是不同的请求,但是太麻烦了,对每个资源我们都要设计对应的权限列然后再塞入到jwt中,对每个用户都要单独授权资源这也是不可取的。

对shiro的改造这里自定义了一些规则:
shiro过滤器链的url=url+"=="+httpMethod
eg:对于url="api/resource/",httpMethod="GET"的资源,其拼接出来的过滤器链匹配url=api/resource==GET
这样对相同的url而不同的访问方式,会判定为不同的资源,即资源不再简单是url,而是url和httpMethod的组合。基于角色的授权模型中,角色所拥有的资源形式为url+"=="+httpMethod
这里改变了过滤器的过滤匹配url规则,重写PathMatchingFilterChainResolver的getChain方法,增加对上述规则的url的支持。

/* *
 * @Author tomsun28
 * @Description 
 * @Date 21:12 2018/4/20
 */
public class RestPathMatchingFilterChainResolver extends PathMatchingFilterChainResolver {
   

    private static final Logger LOGGER = LoggerFactory.getLogger(RestPathMatchingFilterChainResolver.class);

    public RestPathMatchingFilterChainResolver() {
        super();
    }

    public RestPathMatchingFilterChainResolver(FilterConfig filterConfig) {
        super(filterConfig);
    }

    /* *
     * @Description 重写filterChain匹配
     * @Param [request, response, originalChain]
     * @Return javax.servlet.FilterChain
     */
    @Override
    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = this.getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        } else {
            String requestURI = this.getPathWithinApplication(request);
            Iterator var6 = filterChainManager.getChainNames().iterator();

            String pathPattern;
            boolean flag = true;
            String[] strings = null;
            do {
                if (!var6.hasNext()) {
                    return null;
                }

                pathPattern = (String)var6.next();

                strings = pathPattern.split("==");
                if (strings.length == 2) {
                    // 分割出url+httpMethod,判断httpMethod和request请求的method是否一致,不一致直接false
                    if (WebUtils.toHttp(request).getMethod().toUpperCase().equals(strings[1].toUpperCase())) {
                        flag = false;
                    } else {
                        flag = true;
                    }
                } else {
                    flag = false;
                }
                pathPattern = strings[0];
            } while(!this.pathMatches(pathPattern, requestURI) || flag);

            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  Utilizing corresponding filter chain...");
            }
            if (strings.length == 2) {
                pathPattern = pathPattern.concat("==").concat(WebUtils.toHttp(request).getMethod().toUpperCase());
            }

            return filterChainManager.proxy(originalChain, pathPattern);
        }
    }

}

重写PathMatchingFilter的路径匹配方法pathsMatch(),加入httpMethod支持。

/* *
 * @Author tomsun28
 * @Description 重写过滤链路径匹配规则,增加REST风格post,get.delete,put..支持
 * @Date 23:37 2018/4/19
 */
public abstract class BPathMatchingFilter extends PathMatchingFilter {
   

    public BPathMatchingFilter() {

    }
    /* *
     * @Description 重写URL匹配  加入httpMethod支持
     * @Param [path, request]
     * @Return boolean
     */
    @Override
    protected boolean pathsMatch(String path, ServletRequest request) {
        String requestURI = this
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值