关于Shiro 单点登录的功能,我后续还有案例进行教学。今天我们结合前面的一些教程,来做一个完整的Shiro 权限管理综合实例。
简单的权限管理关系图
数据字典
数据库的设计,可以参考http://www.xttblog.com/?p=979。我这里主要设计用户(sys_user)、组织机构(sys_organization)、资源(sys_resource)、角色(sys_role)这几张表。具体可以按照本文末尾附件中的shiro.sql中进行创建。
- 资源:表示菜单元素、页面按钮元素等;菜单元素用来显示界面菜单的,页面按钮是每个页面可进行的操作,如新增、修改、删除按钮;使用type来区分元素类型(如menu表示菜单,button代表按钮),priority是元素的排序,如菜单显示顺序;permission表示权限;如用户菜单使用user:*;也就是把菜单授权给用户后,用户就拥有了user:*权限;如用户新增按钮使用user:create,也就是把用户新增按钮授权给用户后,用户就拥有了user:create权限了;available表示资源是否可用,如菜单显示/不显示。
- 角色:role表示角色标识符,如admin,用于后台判断使用;description表示角色描述,如超级管理员,用于前端显示给用户使用;resource_ids表示该角色拥有的资源列表,即该角色拥有的权限列表(显示角色),即角色是权限字符串集合;available表示角色是否可用。
-
组织机构:name表示组织机构名称,priority是组织机构的排序,即显示顺序;available表示组织机构是否可用。
用户:username表示用户名;password表示密码;salt表示加密密码的盐;role_ids表示用户拥有的角色列表,可以通过角色再获取其权限字符串列表;locked表示用户是否锁定。
为了简单性,如用户-角色,角色-资源关系直接在实体(用户表中的role_ids,角色表中的resource_ids)里完成的,没有建立多余的关系表,如要查询拥有admin角色的用户时,建议建立关联表,否则就没必要建立了。在存储关系时如role_ids=1,2,3,;多个之间使用逗号分隔。
用户组、组织机构组本实例没有实现,即可以把一组权限授权给这些组,组中的用户/组织机构就自动拥有这些角色/权限了;另外对于用户组可以实现一个默认用户组,如论坛,不管匿名/登录用户都有查看帖子的权限。
具体的表结构请查看源代码中的db/shiro-schema.sql (表结构)、db/shiro-data.sql (初始数据)文件。默认用户名/密码是admin/123456。
实现 Realm
public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(userService.findRoles(username)); authorizationInfo.setStringPermissions(userService.findPermissions(username)); System.out.println(userService.findPermissions(username)); return authorizationInfo; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); User user = userService.findByUsername(username); if(user == null) { throw new UnknownAccountException();//没找到帐号 } if(Boolean.TRUE.equals(user.getLocked())) { throw new LockedAccountException(); //帐号锁定 } return new SimpleAuthenticationInfo( user.getUsername(), //用户名 user.getPassword(), //密码 ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt getName() //realm name ); } }
Web层 控制器
@Controller public class IndexController { @Autowired private ResourceService resourceService; @Autowired private UserService userService; @RequestMapping("/") public String index(@CurrentUser User loginUser, Model model) { Set<String> permissions = userService.findPermissions(loginUser.getUsername()); List<Resource> menus = resourceService.findMenus(permissions); model.addAttribute("menus", menus); return "index"; } } @Controller public class LoginController { @RequestMapping(value = "/login") public String showLoginForm(HttpServletRequest req, Model model) { String exceptionClassName = (String)req.getAttribute("shiroLoginFailure"); String error = null; if(UnknownAccountException.class.getName().equals(exceptionClassName)) { error = "用户名/密码错误"; } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) { error = "用户名/密码错误"; } else if(exceptionClassName != null) { error = "其他错误:" + exceptionClassName; } model.addAttribute("error", error); return "login"; } }
Web层 标签库
com.xttblog.shiro15.web.taglib.Functions提供了函数标签实现,有根据编号显示资源/角色/组织机构名称,其定义放在src/main/webapp/tld/xttblog-functions.tld。
其他的dao层,server层,配置文件等我就列举了。具体查看附件源码,导入工程即可运行。下面截取了一些运行效果。
运行效果
附本文源代码下载链接:http://pan.baidu.com/s/1c12WPDQ 密码:vjut
: » 最全的 Shiro demo Shiro 例子
原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/251560.html