spring-shiro权限控制realm实战教程
程序员文章站
2022-03-21 08:37:46
目录realm类shiro 配置类servicespring-shiro权限控制realm用户与角色实体role.java@data@entitypublic class role { @id...
spring-shiro权限控制realm
用户与角色实体
role.java
@data @entity public class role { @id @generatedvalue private integer id; private long userid; private string role; }
user.java
@data @entity public class user { @id @generatedvalue private long id; private string username; private string password; }
realm类
首先建立 realm 类,继承自 authorizingrealm,自定义我们自己的授权和认证的方法。realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件。
realm.java
public class realm extends authorizingrealm { @autowired private userservice userservice; //授权 @override protected authorizationinfo dogetauthorizationinfo(principalcollection principalcollection) { //从凭证中获得用户名 string username = (string) securityutils.getsubject().getprincipal(); //根据用户名查询用户对象 user user = userservice.getuserbyusername(username); //查询用户拥有的角色 list<role> list = roleservice.findbyuserid(user.getid()); simpleauthorizationinfo info = new simpleauthorizationinfo(); for (role role : list) { //赋予用户角色 info.addstringpermission(role.getrole()); } return info; } //认证 @override protected authenticationinfo dogetauthenticationinfo(authenticationtoken authenticationtoken) throws authenticationexception { //获得当前用户的用户名 string username = (string) authenticationtoken.getprincipal(); //从数据库中根据用户名查找用户 user user = userservice.getuserbyusername(username); if (userservice.getuserbyusername(username) == null) { throw new unknownaccountexception( "没有在本系统中找到对应的用户信息。"); } simpleauthenticationinfo info = new simpleauthenticationinfo(user.getusername(), user.getpassword(),getname()); return info; } }
shiro 配置类
shiroconfig.java
@configuration public class shiroconfig { @bean public shirofilterfactorybean shirofilterfactorybean(securitymanager securitymanager) { shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean(); shirofilterfactorybean.setsecuritymanager(securitymanager); map<string, string> filterchaindefinitionmap = new linkedhashmap<string, string>(); //以下是过滤链,按顺序过滤,所以/**需要放最后 //开放的静态资源 filterchaindefinitionmap.put("/favicon.ico", "anon");//网站图标 filterchaindefinitionmap.put("/**", "authc"); shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap); return shirofilterfactorybean; } @bean public defaultwebsecuritymanager securitymanager() { defaultwebsecuritymanager defaultwebsecuritymanager = new defaultwebsecuritymanager(myrealm()); return defaultwebsecuritymanager; } @bean public myrealm myrealm() { myrealm myrealm = new myrealm(); return myrealm; } }
控制器
usercontroller.java
@controller public class usercontroller { @autowired private userservice userservice; @getmapping("/") public string index() { return "index"; } @getmapping("/login") public string tologin() { return "login"; } @getmapping("/admin") public string admin() { return "admin"; } @postmapping("/login") public string dologin(string username, string password) { usernamepasswordtoken token = new usernamepasswordtoken(username, password); subject subject = securityutils.getsubject(); try { subject.login(token); } catch (exception e) { e.printstacktrace(); } return "redirect:admin"; } @getmapping("/home") public string home() { subject subject = securityutils.getsubject(); try { subject.checkpermission("admin"); } catch (unauthorizedexception exception) { system.out.println("没有足够的权限"); } return "home"; } @getmapping("/logout") public string logout() { return "index"; } }
service
userservice.java
@service public class userservice { @autowired private userdao userdao; public user getuserbyusername(string username) { return userdao.findbyusername(username); } @requiresroles("admin") public void send() { system.out.println("我现在拥有角色admin,可以执行本条语句"); } }
shiro权限不生效原因分析
shiro遇到的坑
-项目中使用shiro做登录校验和权限管理,在配置权限时遇到小坑,记录一下。
- 环境:springboot+freemarker+shiro
- 场景:后台管理,配置菜单以及按钮权限,分为三个层级,一二级暂时只考虑是否查看权限,第三层级为页面按钮权限,分增删改查。详情看图
- 问题:一二层级正常,第三层级权限不起作用!
权限标签定义如下:
标签定义 | 页面一 | 页面二 |
---|---|---|
第一层级 | one:view | two:view |
第二层级 | one:page1:view | two:page2:view |
第三层级 | one:page1:view:add | two:page2:view:add |
开始怀疑是数据库没有录入,查看后权限标签与角色已对应,排除。
后面怀疑是页面问题,后面把第三层级标签与第一二层级同一页面,依然不起作用,排除。
后面怀疑是权限标签定义问题,把第三层级标签改为one:page1:data:add,奇迹出现,权限生效。证实权限标签定义出了问题。
问题原因:权限标签定义问题
但是后来想想为什么会出现这种问题,每个标签都是独一无二的,对此我对shiro对于权限标签的校验产生了兴趣,查看源码,一路debug后最终在org.apache.shiro.authz.permission中看到了关键所在,核心代码如下
//当这个方法返回true时说明有此权限 //这个p是代表当前循环匹配到的权限标签 public boolean implies(permission p) { // by default only supports comparisons with other wildcardpermissions if (!(p instanceof wildcardpermission)) { return false; } wildcardpermission wp = (wildcardpermission) p; //把当前标签转分割成一个set集合(如one:page1:view:add 会分割成[[one], [page1], [view], [add]]) list<set<string>> otherparts = wp.getparts(); int i = 0; //循环匹配权限标签 for (set<string> otherpart : otherparts) { // if this permission has less parts than the other permission, everything after the number of parts contained // in this permission is automatically implied, so return true //当全部循环匹配完没有返回false,则返回true,这个getparts()方法是获取当前角色当前循环的权限标签([[one], [page1], [view]]) if (getparts().size() - 1 < i) { return true; } else { set<string> part = getparts().get(i); /*如果包含有‘*'而且不包含当前分割后的标签则返回false, *当用户可以查看页面,也就是说当前角色拥有one:page1:view标签 *这里【!part.contains(wildcard_token)】返回true,第二个【part.containsall(otherpart)】one会跟当前标签匹**配one, *也就是说这里全部循环完返回的都是false,所以最后都没true,于是在上面返回了一个true。 if (!part.contains(wildcard_token) && !part.containsall(otherpart)) { return false; } i++; } }
小结一下:通过分析,我们看到了shiro在定义权限标签时,要主意匹配问题,不要存在包含问题,类似aaa 和aaab ,会导致后面标签失效。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
SQLServer 2005 控制用户权限访问表图文教程
-
ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露
-
JAVAEE——BOS物流项目11:在realm中授权、shiro的方法注解权限控制、shiro的标签权限控制、总结shiro的权限控制方式、权限管理
-
苹果 Mac OS X笔记本控制访问者权限的设置教程
-
spring-shiro权限控制realm实战教程
-
zookeeper权限控制实战
-
Yii2 rbac权限控制操作步骤实例教程,yii2rbac_PHP教程
-
yii2搭建完美后台并实现rbac权限控制案例教程,yii2rbac
-
SQLServer 2005 控制用户权限访问表图文教程
-
基于原生PHP交叉会员权限控制_PHP教程