springboot shiro权限管理【三】:测试框架搭建之shiro授权

授权这块真的是头疼,实现之后返现如此之简单,网上查资料大部分都是认证这里,而授权相关的比较少,再加上springboot整合shiro实现前后台分离授权返回json是真的没看到,后来没办法,只能自己看源码。

列出来下我这里的一个实现过程:(备注:做的是前后端分离的,如果是不分离的就不用重写filter了)

1.有了之前做shiro认证的经验,我猜想到shiro授权,如果授权失败想要返回json格式数据,也是需要重写拦截器的,下面是shiro拦截器:


下面看下shiro PermissionsAuthorizationFiler.java源码实现

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.web.filter.authz;

import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.subject.Subject;

/**
 * Filter that allows access if the current user has the permissions specified by the mapped value, or denies access
 * if the user does not have all of the permissions specified.
 *
 * @since 0.9
 */
public class PermissionsAuthorizationFilter extends AuthorizationFilter {

    //TODO - complete JavaDoc

    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

        Subject subject = getSubject(request, response);
        String[] perms = (String[]) mappedValue;

        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!subject.isPermitted(perms[0])) {
                    isPermitted = false;
                }
            } else {
                if (!subject.isPermittedAll(perms)) {
                    isPermitted = false;
                }
            }
        }

        return isPermitted;
    }
}

看完就明白了吧,里面有个isAccessAllowed方法,中间isPermistted这个属性等于false肯定是授权失败的,然后就可以在这里返回我们要返回给前端的json数据,我们重写它就行了,看代码:

package com.yg.lkyw.interceptor.shiro;

import com.alibaba.fastjson.JSONObject;
import com.yg.lkyw.result.ResultCode;
import org.apache.shiro.subject.Subject;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;

/**
 * @author XXX
 * @version 1.0
 * @Description: shiro拦截器(用于处理用户没有权限访问返回信息)
 * @date 2018年05月08日
 */
public class CustsomPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

        Subject subject = getSubject(request, response);
        String[] perms = (String[]) mappedValue;

        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = null;
            if (perms.length == 1) {
                if (!subject.isPermitted(perms[0])) {
                    //定义未登录返回的json信息
                    Map<String, Object> map = new HashMap<>();
                    map.put("msg", ResultCode.FORBIDDEN.getMsg());
                    map.put("code", ResultCode.FORBIDDEN.getCode());
                    out = response.getWriter();
                    out.write(JSONObject.toJSONString(map));
                    out.flush();
                }
            } else {
                if (!subject.isPermittedAll(perms)) {
                    isPermitted = false;
                    //定义未登录返回的json信息
                    Map<String, Object> map = new HashMap<>();
                    map.put("msg", ResultCode.FORBIDDEN.getMsg());
                    map.put("code", ResultCode.FORBIDDEN.getCode());
                    out = response.getWriter();
                    out.write(JSONObject.toJSONString(map));
                    out.flush();
                }
            }
        }

        return isPermitted;
    }
}

这样就ok了,接下来我们要把自己定义的filter加入到shiro中:

@Configuration  
public class ShiroConfiguration {  
        
     
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。 
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager 
     * 
        Filter Chain定义说明 
       1、一个URL可以配置多个Filter,使用逗号分隔 
       2、当设置多个过滤器时,全部验证通过,才视为通过 
       3、部分过滤器可指定参数,如perms,roles

     * 
     */
    @Bean  
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){  
       System.out.println("ShiroConfiguration.shirFilter()");  
       ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();  
       
       Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//获取filters 
       filters.put("authc", new CustomFormAuthenticationFilter());//自定义返回未登录需要返回给前端的json数据
       filters.put("perms", new CustsomPermissionsAuthorizationFilter()) ;//自定义返回授权失败所需的json提示数据
        // 必须设置 SecurityManager   
       shiroFilterFactoryBean.setSecurityManager(securityManager);  
        
       //拦截器.  
       Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();  
        
       //注意过滤器配置顺序 不能颠倒  
       //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl  
       filterChainDefinitionMap.put("/logout", "logout");  
       // 配置不会被拦截的链接 顺序判断  
       filterChainDefinitionMap.put("/static/**", "anon");  
       filterChainDefinitionMap.put("/ajaxLogin", "anon");  
       filterChainDefinitionMap.put("/system/login", "anon");
       filterChainDefinitionMap.put("/WeChatController/**", "anon");
       //filterChainDefinitionMap.put("/system/user/**", "perms[admin]");//这个是我写死做测试用的,这里要求必须要是admin权限的才可以访问
       filterChainDefinitionMap.put("/**", "authc");

       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);  
       return shiroFilterFactoryBean;  
    }  
     
     
    @Bean  
    public SecurityManager securityManager(){  
       DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();  
       securityManager.setRealm(new ShiroRealm());
       return securityManager;  
    }
}  

下面是我们的realms:

扫描二维码关注公众号,回复: 1591562 查看本文章

package com.yg.lkyw.interceptor.shiro;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;


/**
 * @author 梁荣兵
 * @version 1.0
 * @Description:
 * @date 2018年05月08日
 */
public class ShiroRealm extends AuthorizingRealm {

   /*
    * 登录信息和用户验证信息验证(non-Javadoc)
    * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
    */
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
       String username = (String)token.getPrincipal();            //得到用户名 
        String password = new String((char[])token.getCredentials());     //得到密码
        if(null != username && null != password){
           return new SimpleAuthenticationInfo(username, password, getName());
        }else{
           return null;
        }
   }
   
   /*
    * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法(non-Javadoc)
    * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
      SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
      authorizationInfo.addStringPermission("user");//这里也是写死的,写了一个user权限的,跟上面的admin区分开,为了测试不通过
      return authorizationInfo;
   }

}

shiro授权配置简单实例到这里就ok了

最后提示:用框架,不能单纯用,有空,有兴趣也需要去看看他的实现原理,有问题或建议欢迎留言

 

猜你喜欢

转载自blog.csdn.net/kaola_l/article/details/80681085
今日推荐