授权: 又称访问控制—控制谁有权限在应用程序中做什么。在授权中,需要了解几个关键的对象:Subject 主体、Resource 资源、Permissions 权限、Role 角色:
- Subject 主体:访问应用的用户,在 Shiro 中使用 Subject 代表该用户,用户需要授权后才能访问相应的资源
- Resource 资源:在应用中用户访问的任何东西,例如:jsp、接口、图片等,都属于是资源
- Permissions 权限:Shiro 安全机制最核心的元素。它在应用程序中明确声明了被允许的行为。一个格式良好的权限声明可以清晰表达出用户对该资源拥有的权限。在 Shiro 中主要通过通配符表达式来完成权限的描述
- Role 角色:一个命名的实体, 通常代表一组行为或职责。 这些行为演化为在一个应用中能或者不能做的事情。角色通常分配给用户帐户。一个角色拥有一个权限的集合。授权验证时,需要判断当前角色是否拥有指定的权限。这种角色权限可以对该角色进行详细的权限描述。 Shiro 官方推荐使用这种方式
授权检查的例子: 用户是否能访问某个网页,编辑数据,或打使用这台打印机
授权的三要素: 权限、角色和用户 。
需要在应用程序中对用户和权限建立关联: 通常的做法是将权限分配给角色,然后将角色分配给一个或多个用户。
Shiro 的三种授权方式:
- 编写代码:在 Java 代码中用像 if 和 else 块的结构执行授权检查。
- JDK 的注解:可以添加授权注解给 Java 方法
- JSP 标签库:可以控制基于角色和权限的 JSP 页面输出。
Shiro 授权顺序图:
时序图:
说明:
- Step 1: 应用程序或框架代码调用任何 Subject 的
hasRole*
,checkRole*
,isPermitted*
, 或者checkPermission*
方法的变体,传递任何所需的权限 - Step 2: Subject 的实例—通常是 DelegatingSubject(或子类),调用 securityManager 的对应的方法。
- Step 3: SecurityManager 调用
org.apache.shiro.authz.Authorizer
接口的对应方法。默认情况下,authorizer 实例是一个 ModularRealmAuthorizer 实例,它支持协调任何授权操作过程中的一个或多个 Realm 实例。 - Step 4: 每个配置好的 Realm 被检查是否实现了相同的 Authorizer 接口。如果是,Realm 各自的
hasRole*
,checkRole*
,isPermitted*
,或checkPermission*
方法将被调用。
Shiro 基础语法:Permissions 的声明方式
基础语法之简单的字符串:
- 即用简单的字符串来表示一个权限,如:
user
(相当于:user:*
)
基础语法之多层次管理:
- 例如:
user:query、user:edit
- 多个值:每个部件能够保护多个值。因此,除了授予用户
user:query
和user:edit
权限外,也可以简单地授予他们一个:user:query, edit
- 还可以用
*
号代替所有的值,如:user:*
, 也可以写:*:query
,表示某个用户在所有的领域都有 query 的权限
基础语法之实例级访问控制:
- 这种情况通常会使用三个部件:域、操作、被付诸实施的实例。如:
user:edit:manager
- 也可以使用通配符来定义,如:
user:edit:*、user:*:*、user:*:manager
- 部分省略通配符:缺少的部件意味着用户可以访问所有与之匹配的值,比如:
user:edit
等价于user:edit :*
、user 等价于user:*:*
注意: 通配符只能从字符串的结尾处省略部件,也就是说 user:edit 并不等价于 user:*:edit
Shiro 注销
logout(注销):currentUser.logout();
- 调用 logout() 方法时,现有 Session 将失效,而且身份将失去关联(在 Web 应用程序中,RememberMe cookie 将被删除)。
- 在 Subject 注销后,该 Subject 的实例被再次认为是匿名的。
注意:WEB 应用程序记住身份往往依靠 Cookie,然而 Cookie 只能在 Response 被返回后被删除,所以建议在调用 subject.logout() 后立即向终端重定向一个新的视图或页面。这样即能保证与安全相关的 Cookie 都能像预期的一样被删除。
Realm
- Realm:访问应用程序安全数据(如用户、角色及权限)的组件。
- Realm 通常和数据源是一对一的对应关系,如关系数据库、文件系统或其他类似资源。Realm 实质上就是一个访问安全数据的 DAO。
- 数据源通常存储身份验证数据(如密码的凭证)以及授权数据(如角色或权限),所以每个 Realm 都能够执行身份验证和授权操作。
Realms 的认证实现
Shiro 的认证过程由 Realm 执行,SecurityManager 会调用 org.apache.shiro.realm.Realm
的 getAuthenticationInfo(AuthenticationToken token)
方法
实际开发中,通常会提供 org.apache.shiro.realm.AuthenticatingRealm
的实现类,并在该实现类中提供doGetAuthenticationInfo(AuthenticationToken token)
方法的具体实现
- 检查提交的进行认证的令 ××× 信息
- 根据令 ××× 信息从数据源 (通常为数据库) 中获取用户信息
- 对用户信息进行匹配验证。
- 验证通过将返回一个封装了用户信息的 AuthenticationInfo 实例。
- 验证失败则抛出 AuthenticationException 异常信息。