前言:上一篇文章讲述了如何使用角色url进行粗粒度验证。地址:https://blog.csdn.net/xcc_2269861428/article/details/95768417
这篇说下如何使用perms进行细粒度验证,已经我写代码过程中碰见的坑。
看下角色界面
我在数据库中分别为2个就是设置了perms权限
用户界面
图中可以看出,xcc是没有角色管理权限的,所以不能对角色进行增删改查。
当我用xcc这个用户点击角色部分按钮就会报错。
为xcc分配角色管理权限
再次点击角色部分的按钮,是可以的
为什么要使用perms进行验证呢,因为他很细粒度化,他可以帮助我们精确到每个按钮,并且不需要太多的代码就可以实现。
看下controller部分的代码
package com.waysoft.modules.business.integrate.user.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.waysoft.common.ResponseData;
import com.waysoft.global.model.Menu;
import com.waysoft.global.model.Role;
import com.waysoft.global.model.User;
import com.waysoft.modules.business.integrate.user.service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* @Description 获取数据
* @param request
* @return ResponseData
*/
@RequestMapping(value="login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData save(HttpServletRequest request,User user){
ResponseData responseData=new ResponseData();
try {
responseData = userService.login(user);
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("登录失败");
}
return responseData;
}
/**
* 退出登录
* @param request
* @param user
* @return
*/
@RequestMapping(value="login_out", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData login_out(HttpServletRequest request,User user){
ResponseData responseData=new ResponseData();
try {
Subject subject = SecurityUtils.getSubject();
subject.logout();
responseData.setStatus(0);
responseData.setMsg("退出成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("退出失败");
}
return responseData;
}
/**
* 添加用户
* @param request
* @param user
* @return
*/
@RequiresPermissions(value={"user:add"})
@RequestMapping(value="insertUser", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData insertUser(HttpServletRequest request,User user){
ResponseData responseData=new ResponseData();
try {
userService.insertUser(user);
responseData.setStatus(0);
responseData.setMsg("添加成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("添加失败");
}
return responseData;
}
/**
* 回显用户
* @param request
* @param id
* @return
*/
@RequestMapping(value="getUser/{id}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@RequiresPermissions(value={"user:get"}, logical = Logical.OR)
@ResponseBody
public ResponseData getUser(HttpServletRequest request,@PathVariable("id") String id){
ResponseData responseData=new ResponseData();
try {
User user = userService.getUserById(id);
responseData.setStatus(0);
responseData.setData(user);
responseData.setMsg("获取成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("获取失败");
}
return responseData;
}
/**
* 修改用户
* @param request
* @param user
* @return
*/
@RequiresPermissions(value={"user:update"})
@RequestMapping(value="updateUser", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData updateUser(HttpServletRequest request,User user){
ResponseData responseData=new ResponseData();
try {
userService.updateUser(user);
responseData.setStatus(0);
responseData.setMsg("修改成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("修改失败");
}
return responseData;
}
/**
* 获取菜单
* @param request
* @param id
* @return
*/
@RequiresPermissions(value={"user:getNode"})
@RequestMapping(value="getRole/{id}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData getRole(HttpServletRequest request,@PathVariable("id") String id){
ResponseData responseData=new ResponseData();
try {
List<Menu> menu = userService.getRole(id);
responseData.setStatus(0);
responseData.setData(menu);
responseData.setMsg("获取成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("获取失败");
}
return responseData;
}
/**
* 插入菜单
* @param request
* @param id
* @param urls
* @return
*/
@RequiresPermissions(value={"user:addNode"})
@RequestMapping(value="insertNode", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData insertNode(HttpServletRequest request,String id,String urls){
ResponseData responseData=new ResponseData();
try {
userService.saveNode(id,urls);
responseData.setStatus(0);
responseData.setMsg("添加成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("添加失败");
}
return responseData;
}
@RequestMapping(value="list", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData list(HttpServletRequest request){
ResponseData responseData=new ResponseData();
try {
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("789");
//responseData = userService.login(user);
responseData.setStatus(0);
responseData.setMsg("获取数据成功");
responseData.setData(list);
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("获取数据失败");
}
return responseData;
}
}
package com.waysoft.modules.business.integrate.role.controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.waysoft.common.ResponseData;
import com.waysoft.global.model.Menu;
import com.waysoft.global.model.Role;
import com.waysoft.modules.business.integrate.role.service.RoleService;
@Controller
@RequestMapping("/role")
public class RoleController {
@Autowired
private RoleService roleService;
/**
* 添加角色
* @param request
* @param role
* @return
*/
@RequiresPermissions("role:add")
@RequestMapping(value="insertRole", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData insertRole(HttpServletRequest request,Role role){
ResponseData responseData=new ResponseData();
try {
roleService.insertRole(role);
responseData.setStatus(0);
responseData.setMsg("添加成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("添加失败");
}
return responseData;
}
/**
* 回显角色
* @param request
* @param id
* @return
*/
@RequiresPermissions("role:get")
@RequestMapping(value="getRole/{id}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData getRole(HttpServletRequest request,@PathVariable("id") String id){
ResponseData responseData=new ResponseData();
try {
Role role = roleService.getRole(id);
responseData.setStatus(0);
responseData.setData(role);
responseData.setMsg("获取成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("获取失败");
}
return responseData;
}
/**
* 修改角色
* @param request
* @param role
* @return
*/
@RequiresPermissions("role:update")
@RequestMapping(value="updateRole", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData updateRole(HttpServletRequest request,Role role){
ResponseData responseData=new ResponseData();
try {
roleService.updateRole(role);
responseData.setStatus(0);
responseData.setMsg("修改成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("修改失败");
}
return responseData;
}
/**
* 获取菜单
* @param request
* @param id
* @return
*/
@RequiresPermissions("role:getNode")
@RequestMapping(value="getMenu/{id}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData getMenu(HttpServletRequest request,@PathVariable("id") String id){
ResponseData responseData=new ResponseData();
try {
List<Menu> menu = roleService.getMenu(id);
responseData.setStatus(0);
responseData.setData(menu);
responseData.setMsg("获取成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("获取失败");
}
return responseData;
}
/**
* 插入菜单
* @param request
* @param id
* @param urls
* @return
*/
@RequiresPermissions("role:addNode")
@RequestMapping(value="insertNode", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseData insertNode(HttpServletRequest request,String id,String urls){
ResponseData responseData=new ResponseData();
try {
roleService.saveNode(id,urls);
responseData.setStatus(0);
responseData.setMsg("添加成功");
}catch(Exception e){
responseData.setStatus(1);
responseData.setMsg("添加失败");
}
return responseData;
}
}
方法上我基本上都加入了权限验证 @RequiresPermissions("role:add")
由于我都是从数据库中读取的,所以我需要重写AuthorizingRealm
package com.waysoft.common.shiro;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import com.waysoft.global.model.User;
import com.waysoft.modules.business.integrate.role.dao.RoleDao;
import com.waysoft.modules.business.integrate.user.service.UserService;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private RoleDao roleDao;
/**
* 授权验证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("=============");
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
User user = (User)session.getAttribute("user");
String[] ids = userService.getRoleIdByUserId(user.getId()+"");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if(ids.length > 0){
List<String> asList = Arrays.asList(ids);
info.addRoles(asList);
for(String id : asList){
String permsName = roleDao.getPermsByid(id);
String perms [] = permsName.split(",");
for(String prem :perms){
info.addStringPermission(prem);
}
}
return info;
}
return null;
}
/**
* 登录验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 账户名
String username = (String) authenticationToken.getPrincipal();
User user = userService.findUser(username);
if(user != null){
return new SimpleAuthenticationInfo(username,user.getPassword(),null,getName());
}else{
return null;
}
}
}
网上有很多种方法可以插入权限信息,但我用都不好使。比如:info.addStringPermissions(permissions);,没成功过,也在这卡了半天。最后我是使用addStringPermission实现的,原本我还有以为这样循环会覆盖原来的值,经测试,并没有。
之后就是重写PermissionsAuthorizationFilter
这个真是太坑了。差点被他搞死,看下源码
画红框的就是坑,它所验证的是一个,或者全部符合,是全等关系,而不是包含关系。
我要重写成包含关系
有一个符合就通过。
自定义ShiroFilterFactoryBean
package com.waysoft.common.shiro;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
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 com.waysoft.modules.business.integrate.role.dao.RoleDao;
public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {
private static final String roles = "authc,perms[{0}]";
// perms
@Autowired
private RoleDao roleDao;
@Override
public void setFilterChainDefinitions(String definitions) {
//System.out.println("权限认证");
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection("urls");
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection("");
}
Map<String,String> data = new HashMap<String,String>();
// 从数据读取出数据
List<Map<String,String>> menuRole = roleDao.getPerms_();
for(Map<String,String> map : menuRole){
if(data.containsKey(map.get("url"))){
String str = data.get(map.get("url"))+","+map.get("perms_");
data.put(map.get("url"), str);
}else{
data.put(map.get("url"), map.get("perms_"));
}
}
for(String url : data.keySet()){
String str = MessageFormat.format(roles,data.get(url));
System.out.println(url+"="+str);
section.put(url, str);
}
section.put("/**", "authc");
super.setFilterChainDefinitionMap(section);
}
public void update(){
synchronized (this) {
try {
AbstractShiroFilter shiroFilter = (AbstractShiroFilter)this.getObject();
PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver)shiroFilter.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager)resolver.getFilterChainManager();
manager.getFilterChains().clear();
this.getFilterChainDefinitionMap().clear();
Map<String, String> chains = this.getFilterChainDefinitionMap();
Map<String,String> data = new HashMap<String,String>();
// 从数据读取出数据
List<Map<String,String>> menuRole = roleDao.getPerms_();
for(Map<String,String> map : menuRole){
if(data.containsKey(map.get("url"))){
String str = data.get(map.get("url"))+","+map.get("perms_");
data.put(map.get("url"), str);
}else{
data.put(map.get("url"), map.get("perms_"));
}
}
for(String url : data.keySet()){
String str = MessageFormat.format(roles,data.get(url));
chains.put(url, str);
}
chains.put("/**", "authc");
if (!(CollectionUtils.isEmpty(chains))) {
for (Map.Entry entry : chains.entrySet()) {
String url = (String) entry.getKey();
String chainDefinition = (String) entry.getValue();
manager.createChain(url, chainDefinition);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
System.out.println(MessageFormat.format(roles,2));
}
}
还有就是要在xml中加入如下内容,否则注解不起作用
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
资料下载地址:https://download.csdn.net/download/xcc_2269861428/11348378