关于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配置的问题,前缀一定加/,所以路径很重要,重要的事情再说一遍,前缀一定要加/,否则你的拦截会失效!!!!