1、授权实现方式
1.1、什么是授权
授权包含4个元素(一个比较流行通用的权限模型)
Resources:资源
各种需要访问控制的资源Permissions:权限
安全策略控制原子元素 基于资源和动作 控制力度Roles:角色
行为的集合User:用户主体
Subject,关联Role或Permission简单来说,可以这样理解:我们登录进系统,我们就是一个【用户】;【用户】可以是一个或多个【角色】,一个【角色】可以有多种【权限】,这些【权限】代表了我们可以访问哪些【资源】。当然【用户】也可以直接跳过【角色】,直接给【用户】分配【权限】,表明这个【用户】可以访问的【资源】。
1.2、授权方式
a、编程模型
基于Role
Role校验
API: hasRole(String roleName) hasRoles(List<String> roleNames) hasAllRoles(Collection<String> roleNames)Subject currentUser = SecurityUtils.getSubject();if(currentUser.hasRole("admin")){ ...} else{ ...}
Role断言(Assertion)
失败会抛出异常AuthorizationException API checkRole(String roleName) checkRoles(Collection<String> roleNames) checkRoles(String... roleNames)Subject currentUser = SecurityUtils.getSubject();currentUser.checkRole("bankTeller");openBankAccount();
基于Permission
Permission校验
基于对象的Permission校验 应用场景:显式控制、类型安全 API isPermiited(Permission p) isPermiited(List<Permission> perms) isPermiitedAll(Collection<Permission> perms)Permission printPermission = new PrinterPermission("hp","print");Subject currentUser = SecurityUtils.getSubject();if(currentUser.isPermitted(printPermission)){ ...} else { ...}
基于String的Permission校验
应用场景:轻量级、简单 API isPermiited(String perm) isPermiited(String... perms) isPermiitedAll(String... perms)Subject currentUser = SecurityUtils.getSubject();if(currentUser.isPermitted("printer:print:hp")){ ...} else { ...}
Permission断言(Assertion)
失败会抛出异常AuthorizationException API checkPermission(Permission p)) checkPermission(String perm) checkPermissions(Collection<Permission> perms) checkPermissions(String... perms)Subject currentUser = SecurityUtils.getSubject();Permission p = new AccountPermission("open");current.checkPermission(p);openBankAccount();
b、JDK注解
@RequiresAuthentication
用于判断是否已认证,未认证访问该资源会抛异常,下面代码效果相同
@RequiresAuthenticationpublic void updateAccount(Account userAccount){ ...}public void updateAccount(Account userAccount){ if(!SecurityUtils.getSubject().isAuthenticated()){ throw new AuthorizationException(...); }}
@RequiresGuest
用于判断是否为游客,如果非游客会抛异常,下面代码效果相同
@RequiresGuestpublic void signUp(User newUser){ ...}public void signUp(User newUser){ Subject currentUser = SecurityUtils.getSubject(); PrincipalCollection principals = currentUser.getPrincipals(); if(principals != null && !principals.isEmpty()){ throw new AuthorizationException(...); }}
@RequiresPermissions
用于判断有该权限才能访问,下面代码效果相同
@ReruiresPermissions("account:create")public void creatAccount(Account account){ ...}public void creatAccount(Account account){ Subject currentUser = SecurityUtils.getSubject(); if(!subject.isPermitted("account:create")){ throw new AuthorizationException(...); }}
@RequiresRoles
用于判断有该角色才能访问,下面代码效果相同
@RequiresRoles("admin")public void deleteUser(User user){ ...}public void deleteUser(User user){ Subject currentUser = SecurityUtils.getSubject(); if(!subject.hasRole("admin")){ throw new AuthorizationException(...); }}
@RequiresUser
用于判断非游客才能访问,下面代码效果相同
@RequiresUserpublic void updateAccount(Account account){ ...}public void updateAccount(Account account){ Subject currentUser = SecurityUtils.getSubject(); PrincipalCollection principals = currentUser.getPrincipals(); if(principals == null || principals.isEmpty()){ throw new AuthorizationException(...); }}
c、JSP/GSP TagLibs
偏向web,不介绍
2、授权架构
1、调用Subject的isPermitted或HasRole方法
2、找Security Manager(门面模式)
3、调用Authorizer组件
4、通过Realm访问数据库等获取数据,用于判断是否有授权
Authorizer
默认实现ModularRealmAuthorizer
迭代授权多个Realm
策略
如果一个Realm不实现Authorizer,不校验
如果一个Realm实现Authorizer
一旦校验失败,马上抛AuthorizationException
一旦校验成功,马上返回true
PermissionResolver权限解析器
用于将Permission字符串解析成Permission对象,Shiro内部都是使用Permission对象来进行验证
默认WildcardPermissionResolver(通配符权限解析器)
可以自定义解析器
RolePermissionResolver
用于将Role字符串转换为Permission对象
可以自定义解析器