关于shiro授权不调用(或者需要重启服务器才生效)的陷阱

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011267841/article/details/81029248

 关于shiro的配置我不多说了,现在说一下更改权限后要重启服务器的问题

web.xml

  <filter>
    <filter-name>myShiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>myShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

ShiroConfig.java

    @Bean(name = "myShiroFilter")
    public ShiroFilterFactoryBean myShiroFilter() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置登录链接(前后端分离方案中这里不返回页面,返回403报文,供前端跳转到登录页面)
        //如果不配置,默认跳到登录页面
        shiroFilterFactoryBean.setLoginUrl("/403");
        // 登录成功后要跳转的链接(前后端分离方案这个不需要)
        //shiroFilterFactoryBean.setSuccessUrl("/home");
        // 未授权跳转链接;
        shiroFilterFactoryBean.setUnauthorizedUrl("/401");

        //拦截链配置
        Map<String, String> filterChainDefinitionMap = constructFilterChainDefinitionMap();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        log.info("ShiroFilterFactoryBean注入成功!");
        return shiroFilterFactoryBean;
    }
  /**
     * 构造shiro过滤链配置
     * */
    private Map<String,String> constructFilterChainDefinitionMap(){
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //动态加载url权限配置,从数据库获取
        List<SysAccessPermissionTest> list = sysAccessPermissionServiceImpl.getAll();
        for (SysAccessPermissionTest item : list) {
            filterChainDefinitionMap.put(item.getUrl(),item.getRoles());
        }

        return filterChainDefinitionMap;
    }

ShiroConfigServer.java的更新权限的方法

public void updateMyPermission() {
        synchronized (shiroFilterFactoryBean) {
        	
            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
                        .getObject();
            } catch (Exception e) {
                throw new RuntimeException(
                        "get ShiroFilter from shiroFilterFactoryBean error!");
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();

            // 清空老的权限控制
            manager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions());

            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            //System.out.println("chains-------"+chains);
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim().replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
            log.info("更新权限成功!!");
        }
    }
注意:
updateMyPermission()的方法是更新权限的操作,红色的部分要去掉,这样才可以不用重启服务,ShiroConfigServer.java 完整的方法
package com.gameloft9.demo.security;


import com.gameloft9.demo.service.api.system.SysAccessPermissionService;
import com.gameloft9.demo.dataaccess.model.system.SysAccessPermissionTest;
import lombok.extern.slf4j.Slf4j;


import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;


import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;


/**
 * shiro 动态权限配置相关服务
 * @author gameloft9
 */
@Service
@Slf4j
public class ShiroConfigService {


    @Autowired
    ShiroFilterFactoryBean shiroFilterFactoryBean;
    
    


    @Autowired
    SysAccessPermissionService sysAccessPermissionServiceImpl;


    /**
     * 从数据库加载权限列表
     */
    public Map<String, String> loadFilterChainDefinitions() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        List<SysAccessPermissionTest> list = sysAccessPermissionServiceImpl.getAll();
        for (SysAccessPermissionTest item : list) {
            filterChainDefinitionMap.put(item.getUrl(), item.getRoles());
        }
        return filterChainDefinitionMap;
    }


    /**
     * 更新权限(已废弃),会造成要重启才能生效权限
     */
    @Deprecated
    public void updateMyPermission() {
        synchronized (shiroFilterFactoryBean) {
        	
            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
                        .getObject();
            } catch (Exception e) {
                throw new RuntimeException(
                        "get ShiroFilter from shiroFilterFactoryBean error!");
            }


            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();


            // 清空老的权限控制
            manager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions());


            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            //System.out.println("chains-------"+chains);
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim().replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
            log.info("更新权限成功!!");
        }
    }
    
    /**
     * 更新权限,解决需要重启tomcat才能生效权限的问题
     */
    public void updatePermission() {
    	try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            ServletContext servletContext = request.getSession().getServletContext();
            AbstractShiroFilter shiroFilter = (AbstractShiroFilter) WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getBean("myShiroFilter");          
            
            //ShiroFilterFactoryBean shiroFilter = (ShiroFilterFactoryBean) WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getBean("myShiroFilter");
            
            synchronized (shiroFilter) {
                // 获取过滤管理器
                PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
                DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();             
                // 清空初始权限配置
                manager.getFilterChains().clear();
                // 重新获取资源
                Map<String, String> chains = loadFilterChainDefinitions();
               // System.out.println("chains-------"+chains);
                for (Map.Entry<String, String> entry : chains.entrySet()) {
                    String url = entry.getKey();
                    String chainDefinition = entry.getValue().trim().replace(" ", "");
                    //System.out.println(url+"\t-----> "+chainDefinition);
                    manager.createChain(url, chainDefinition);
                }
                log.info("更新权限成功!!");
            }
        } catch (Exception e) {
            log.error(e.getMessage());


    


	}
   }
}

再说一下不走授权doGetAuthorizationInfo方法,我的ShiroRealm完整文件如下

package com.gameloft9.demo.security;

import com.gameloft9.demo.service.api.system.SysUserService;
import com.gameloft9.demo.dataaccess.model.system.UserTest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.List;

/**
 * 认证授权。
 * @author gameloft9
 */
@Slf4j
@Data
public class ShiroRealm extends AuthorizingRealm {

	/**
	 * 通过setter注入,这里没有通过@Autowired注入
	 * */
	private SysUserService userServiceImpl;

	/**
	 * 获取授权信息方法,返回用户角色信息
	 * */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		if (principals == null) {
			throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
		}

		UserTest user = (UserTest) principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		if (user != null) {//获取用户角色信息
			List<String> roles = userServiceImpl.getRoleNames(user.getId());
			info.addRoles(roles);
		} else {
			SecurityUtils.getSubject().logout();
		}
		return info;
	}

	/**
	 * 重写回调认证方法,subject.login()调用后回调此方法,获取认证信息。
	 * 如果是与第三方用户系统集成,可在此处进行身份认证,成功后可构造一个同登录token一致的认证信息。
	 * 或者干脆跳过shiro的认证,自己实现认证逻辑,成功后将用户信息放入session、cookie.
	 * */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		UserTest user = userServiceImpl.getByLoginName(token.getUsername());

		if (user == null) {//用户不存在
			throw new UnknownAccountException();
		}

		//构造一个用户认证信息并返回,后面会通过这个和token的pwd进行对比。
		return new SimpleAuthenticationInfo(user,user.getPassword(),user.getRealName());
	}
}

网上所说的都不适用,例如:

1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;

2、@RequiresRoles("admin") :在方法上加注解的时候;

3、[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。

在所有的代码检查完后,如果不是这方面的原因,很可能是你配置的权限url规则有问题,请看图


小伙伴们发现了什么问题了吗,下面的是执行后台请求的路径前缀,例如sysUser/list.do,一定要在前面加/


没错就是url配置的问题,前缀一定加/,所以路径很重要,重要的事情再说一遍,前缀一定要加/,否则你的拦截会失效!!!!

猜你喜欢

转载自blog.csdn.net/u011267841/article/details/81029248