本节讲权限认证,也就是授权
基于角色的访问控制和基于权限的访问控制的小实例
以及注解式授权和JSP标签授权详解
权限认证
权限认证核心要素
权限认证,也就是访问控制,即在应用中控制谁能访问哪些资源
在权限认证中,最核心的三个要素是:权限,角色和用户 (资源也算一个要素,但不是最核心的)
权限,即操作资源的 权限,比如访问某个页面,以及对某个模块的数据的添加,修改,删除,查看的权利(整合以后,其实就是一些对URL请求的权限)
角色,是权限的集合,一种角色可以包含多种权限(将权限赋给角色)
用户,在Shiro中,代表访问系统的用户,即Subject(将角色赋给用户)
英文好的,可以去看官方文档介绍: http://shiro.apache.org/authorization.html
授权
编程式授权(Programmatic Authorization)
—-基于角色的访问控制
首先配置ini文件:
[users] ;基于角色的访问控制的配置文件 chx=123456,role1,role2 ;加角色,密码后面是拥有的角色 jack=123456,role1
测试类
package cn.chenhaoxiang.shiro; import cn.chenhaoxiang.common.ShiroUtils; import org.apache.shiro.subject.Subject; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; /** * 基于角色的访问控制 */ public class RoleTest { private static Logger logger = LoggerFactory.getLogger(RoleTest.class); /** * hasRole(String roleName) Returns true if the Subject is assigned the specified role, false otherwise. * hasRoles(List<String> roleNames) Returns a array of hasRole results corresponding to the indices in the method argument. Useful as a performance enhancement if many role checks need to be performed (e.g. when customizing a complex view) * hasAllRoles(Collection<String> roleNames) Returns true if the Subject is assigned all of the specified roles, false otherwise. * hasRole 判断是否拥有某个角色 * * hasRoles 判断拥有某个角色 返回的是boolean[] 用来高效判断对应角色拥有 * hasAllRoles 判断拥有所有角色 拥有传入的全部角色的话,才返回true * */ @Test public void testHasRole(){ Subject subject = ShiroUtils.login("classpath:shiro_role.ini","chx","123456"); logger.info(subject.hasRole("role1")?"有role1这个角色":"没有role1这个角色"); logger.info(subject.hasRole("role2")?"有role2这个角色":"没有role2这个角色"); Subject subject2 = ShiroUtils.login("classpath:shiro_role.ini","jack","123456"); logger.info(subject2.hasRole("role1")?"有role1这个角色":"没有role1这个角色"); logger.info(subject2.hasRole("role2")?"有role2这个角色":"没有role2这个角色"); // hasRoles 判断拥有某个角色 返回的是boolean[] 用来高效判断对应角色拥有 boolean[] results = subject.hasRoles(Arrays.asList("role1","role2","role3")); logger.info(results[0]?"有role1这个角色":"没有role1这个角色"); logger.info(results[1]?"有role2这个角色":"没有role2这个角色"); logger.info(results[2]?"有role2这个角色":"没有role3这个角色"); //hasAllRoles 判断拥有所有角色 拥有传入的全部角色的话,才返回true logger.info(subject.hasAllRoles(Arrays.asList("role1","role2"))?"有role1和role2这两个个角色":"role1,role2这两个角色不全部有"); subject.logout();//退出 } /** * CheckRole */ @Test public void testCheckRole(){ Subject subject = ShiroUtils.login("classpath:shiro_role.ini","chx","123456"); subject.checkRole("role1");//没有返回值 //subject.checkRole("role3");//没有这个角色会抛出异常 //org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role211] //checkRoles(Collection<String> roleNames) subject.checkRoles(Arrays.asList("role1","role2")); //subject.checkRoles(Arrays.asList("role1","role2","role3"));//没有全部角色会抛出异常 //org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role3] //checkRoles(String... roleNames)和checkRoles(Collection<String> roleNames)意思一样,传入的参数类型不同 subject.checkRoles("role1","role2"); subject.logout();//退出 } }
演示结果自己跑一遍就出来啦
—-基于权限的访问控制
配置ini文件:
[users] ;基于权限的访问控制的配置文件 chx=123456,role1,role2 ;加角色,密码后面是拥有的角色 jack=123456,role1 [roles] ;不判断角色,直接判断权限 role1=user:select ;role1拥有select权限 这里的user:select权限名字是自己定义的 role2=user:add,user:update,user:delete ;权限无非就是增删改查
测试类:
package cn.chenhaoxiang.shiro; import cn.chenhaoxiang.common.ShiroUtils; import org.apache.shiro.subject.Subject; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 基于权限的访问控制 */ public class PermissionTest { private static Logger logger = LoggerFactory.getLogger(PermissionTest.class); /** * isPermitted(Permission p) isPermitted(String str) 如果是拥有访问某个资源的权限,返回true 单个权限判断 * * isPermitted(String... var1); 分别判断多个权限 返回boolean[] * * isPermittedAll(String... var1); 拥有所有权限才返回true */ @Test public void testIsPermitted(){ //Subject subject = ShiroUtils.login("classpath:shiro_permission.ini","chx","123456"); Subject subject = ShiroUtils.login("classpath:shiro_permission.ini","jack","123456"); logger.info(subject.isPermitted("user:select")?"有user:select权限":"没有user:select权限"); logger.info(subject.isPermitted("user:update")?"有user:update权限":"没有user:update权限"); boolean results[] = subject.isPermitted("user:select","user:update","user:delete"); logger.info(results[0]?"有user:select权限":"没有user:select权限"); logger.info(results[1]?"有user:update权限":"没有user:update权限"); logger.info(results[2]?"有user:delete权限":"没有user:delete权限"); logger.info(subject.isPermittedAll("user:select","user:update")?"有user:select和user:update权限":"user:select和user:update权限不全有"); subject.logout();//退出 } /** * * checkPermission(String var1) 没有这一个权限就抛出异常 * checkPermissions(String... var1) 没有这些权限就抛出异常 */ @Test public void testCheckPermitted(){ //Subject subject = ShiroUtils.login("classpath:shiro_permission.ini","chx","123456"); Subject subject = ShiroUtils.login("classpath:shiro_permission.ini","jack","123456"); subject.checkPermission("user:select");//检查是否有某个权限 没有权限则抛出异常 //subject.checkPermission("user:delete");//org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:delete] subject.checkPermissions("user:select","user:update"); subject.logout();//退出 } }
讲了几个org.apache.shiro.subject.Subject的函数。
其实官方文档都有介绍的
注解式授权
更加详细的介绍可以去官网查看: http://shiro.apache.org/authorization.html
首先你的Java版本5+才能集成shiro的注解
RequiresAuthentication注解
RequiresAuthentication注解需要在当前会话中对当前的Subject进行身份验证,以便访问或调用该注解的类/实例/方法。
也就是要求当前Subject已经在当前的Session中被验证通过才能被访问或调用
比如:
@RequiresAuthentication //判断验证有没有通过 public void updateAccount(Account userAccount) { //this method will only be invoked by a //Subject that is guaranteed authenticated ... }
基本等同于下面的代码:
public void updateAccount(Account userAccount) { if (!SecurityUtils.getSubject().isAuthenticated()) { throw new AuthorizationException(...); } //Subject is guaranteed authenticated here ... }
RequiresGuest注解
要求当前的Subject是一个’guest’(游客),也就是说,必须是在之前的session中没有被验证或被记住才能被访问和调用
例如:
@RequiresGuest public void signUp(User newUser) { //this method will only be invoked by a //Subject that is unknown/anonymous ... }
基本等价于下面的代码:
public void signUp(User newUser) { Subject currentUser = SecurityUtils.getSubject(); PrincipalCollection principals = currentUser.getPrincipals(); if (principals != null && !principals.isEmpty()) { //known identity - not a guest: throw new AuthorizationException(...); } //Subject is guaranteed to be a 'guest' here ... }
RequiresPermissions注解
RequiresPermissions注解要求当前Subject允许一个或多个权限来执行带注释的方法。
也就是说,必须有这个权限才能访问
例如:
@RequiresPermissions("account:create") //必须有account:create权限,多个权限之间用逗号隔开 public void createAccount(Account account) { //this method will only be invoked by a Subject //that is permitted to create an account ... }
基本等价于:
public void createAccount(Account account) { Subject currentUser = SecurityUtils.getSubject(); if (!subject.isPermitted("account:create")) { throw new AuthorizationException(...); } //Subject is guaranteed to be permitted here ... }