在进行Shiro授权之前,了解相关术语对于理解整个过程至关重要。Shiro的授权机制以角色为中心,辅以权限,来控制主体对资源的访问。以下是常用术语的简要介绍:
-
授权 (Authorization)
授权是指确定主体是否有权访问某一资源或执行某一操作。通过角色和权限机制,Shiro为系统提供了细粒度的访问控制能力 -
主体 (Subject)
主体是指当前的用户、设备或其他能与应用进行交互的实体。每个主体在登录后,会被分配一定的权限和角色来确定其行为 -
资源 (Resource)
资源可以是系统中的任意数据或服务,例如文件、API接口等,主体通过权限来访问这些资源 -
权限 (Permission)
权限是允许主体执行某个具体操作的规则。Shiro的权限是基于字符串的,可以通过自定义规则实现不同的访问控制策略 -
角色 (Role)
角色是权限的集合,主体通过被分配某些角色来获得一系列权限。例如,一个"管理员"角色可能包含创建、更新、删除等权限 -
隐式角色 (Implicit Role)
隐式角色是指由系统规则自动分配的角色,无需明确配置。通常基于上下文、属性等信息动态确定 -
显式角色 (Explicit Role)
显式角色是通过明确配置的角色,例如在数据库中定义或直接在代码中指定的角色
1. 授权
授权是Shiro中重要的核心功能,通过角色和权限实现系统的安全控制
(1) 授权流程
Shiro的授权过程分为以下几步:
-
主体登录
主体通过身份验证(认证)后,进入授权流程。Shiro通过Subject
对象获取当前用户信息 -
权限检查
当主体尝试访问某一资源时,Shiro首先通过SecurityManager
查询该主体的权限信息。系统会根据配置的Realm
来判断主体是否有权限 -
角色检查
若主体的权限不足,Shiro还会查询主体所属的角色,检查该角色是否具备访问资源的权限 -
结果返回
根据查询结果,Shiro决定是否允许主体访问对应资源。如果授权失败,Shiro会抛出UnauthorizedException
异常
(2) 授权方式
Shiro支持多种授权方式,满足不同系统需求
-
基于角色的授权
通过角色为主体赋予一组权限,这种方式适合结构清晰、权限划分明确的场景subject.hasRole("admin") //判断主体是否拥有“admin”角色
-
基于权限的授权
直接为主体赋予特定的权限,通常使用字符串标识权限,具有高度灵活性subject.isPermitted("file:read")//判断主体是否具备“文件读取”的权限
-
基于注解的授权
Shiro还提供了注解方式,通过注解可以直接在控制器、服务方法中指定授权规则@RequiresRoles("admin") 或 @RequiresPermissions("user:update")
2. SpringBoot+Shiro授权
将Shiro与SpringBoot集成是目前比较主流的实践,通过简单的配置即可为SpringBoot项目增加灵活的授权控制
(1) 静态授权
静态授权是指在代码或配置文件中提前定义好角色和权限的关系,不依赖运行时动态数据。这种方式适合权限结构简单的场景
-
配置静态授权规则
在Shiro的配置文件中为不同角色配置权限:shiro: roles: admin: "file:create,file:read,file:update" user: "file:read"
-
代码中基于角色或权限的判断
在代码中可以使用以下方式进行静态授权:System.out.println("调用MyShiroRealm的doGetAuthorizationInfo获取权限信息"); //获得权限信息 User user = (User) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRole(user.getRole().getRoleName()); info.addStringPermission("用户列表"); //管理增删改 if ("管理员".equals(user.getRole().getRoleName())) { info.addStringPermission("用户添加"); info.addStringPermission("用户编辑"); info.addStringPermission("用户删除"); }
(2) 动态授权
动态授权通过数据库或外部服务来实现对权限的实时控制。此方式更加灵活,适合权限体系复杂、需要频繁调整权限的场景
-
动态角色与权限的加载
通过自定义Realm
从数据库中加载角色和权限:System.out.println("调用MyShiroRealm的doGetAuthenticationInfo获取身份信息"); //获得身份信息 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String usrName = token.getUsername(); User user = userService.getUserByUsrName(usrName); if (user == null) { throw new AuthenticationException();//账号错误 } if (user.getUsrFlag() == null || user.getUsrFlag().intValue() == 0) { throw new LockedAccountException();//账号被禁用 } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo( user, user.getUsrPassword(), getName());
-
结合动态数据判断
使用动态方式可以根据业务需求实时调整权限,例如根据用户角色动态生成权限菜单Subject currentUser = SecurityUtils.getSubject(); // 动态判断用户是否有管理员角色 if (currentUser.hasRole("admin")) { return "你好admin"; } else { return "角色不存在!"; }