Apache Shiro Authorization学习笔记

Authorization(授权)机制

Authorization的三元素:权限、角色、用户。

Permissions:权限状态仅仅代表行为。并不指代与用户、角色的关联。

Roles:Implicit roles,隐式构造角色,应用中包含的行为限定于一套角色,不用声明角色名。(缺点:在修改权限时,需要重新修改代码。)

             Excplcit roles,显式构造角色,本质上是一个权限集合。

Users:用户,由Relam来进行权限的判定。


Authorization的三种表现形式:

    1.代码中直接编写,例如if……else……。

    2.通过JDK的annotation进行权限设定与判断。

    3.Jsp/Gsp 的taglib来进行权限的设定与判断。

    (比较简易的方法是对用户进行初始化时授权)


用户角色的判定:

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.hasRole("administrator")) {
    //show the admin button
} else {
    //don't show the button?  Grey it out?
}

    1.hasRole(String roleName) 用户拥有此角色返回TRUE,否则为FALSE;

    2.hasRoles(List<String> roleNames) 用户拥有此角色列表中某几个,则执行此角色权限;

    3.hasAllRoles(Collection<String> roleNames) 用户拥有列表中所有角色返回TRUE,否则为FALSE。

用户角色的检测(Assertions,断言判定):

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is a bank teller and
//therefore allowed to open the account:
currentUser.checkRole("bankTeller");
openBankAccount();

    1.checkRole(String roleName) 用户拥有此角色继续执行,否则抛出AuthorizationException异常;

    2.checkRoles(Collection<String> roleNames) 用户拥有列表中所有角色继续执行,否则抛出AuthorizationException异常;

    3.checkRoles(String... roleNames) 和checkRoles方法类似,可以用var-args格式参数。


权限判定:

    1.实例化org.apache.shiro.authz.Permission接口,

Permission printPermission = new PrinterPermission("laserjet4400n", "print");

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted(printPermission)) {
    //show the Print button
} else {
    //don't show the button?  Grey it out?
}

    isPermitted(Permission p) 用户有此权限返回TRUE,否则为FALSE;

    isPermitted(List<Permission> perms) 用户拥有列表中某些权限,则执行此权限;

    isPermittedAll(Collection<Permission> perms) 用户拥有所有权限返回TRUE,否则为FALSE。

    2.用一个String来限定权限

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted("printer:print:laserjet4400n")) {
    //show the Print button
} else {
    //don't show the button?  Grey it out?
}

    3.org.apache.shiro.authz.permission.WildcardPermission的实现(可以自定义自己的权限标识模型)

Subject currentUser = SecurityUtils.getSubject();

Permission p = new WildcardPermission("printer:print:laserjet4400n");

if (currentUser.isPermitted(p) {
    //show the Print button
} else {
    //don't show the button?  Grey it out?
}

    isPermitted(String perm) 用户拥有此权限返回TRUE,否则返回FALSE;

    isPermitted(String... perms) 用户拥有所有权限中几个,执行此权限;

    isPermittedAll(String... perms) 用户拥有所有权限返回TRUE,否则为FALSE。

权限检测(权限的断言判定):

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted
//to open a bank account:
Permission p = new AccountPermission("open");
currentUser.checkPermission(p);
openBankAccount();

或者,

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted
//to open a bank account:
currentUser.checkPermission("account:open");
openBankAccount();

    1.checkPermission(Permission p) 用户拥有此权限则继续执行,否则抛出AuthorizationException异常;

    2.checkPermission(String perm) 与上面方法相同,只是参数类型不同;

    3.checkPermissions(Collection<Permission> perms) 用户拥有所有权限则继续执行,否则抛出AuthorizationException异常;

    4.checkPermissions(String... perms) 与上面方法相似,只是参数不同。


Authorization基于Annotation

案例一(认证角色验证):

@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
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("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
    ...
}

案例四(超级管理员角色验证):

@RequiresRoles("administrator")
public void deleteUser(User user) {
    //this method will only be invoked by an administrator
    ...
}

    等同于

public void deleteUser(User user) {
    Subject currentUser = SecurityUtils.getSubject();
    if (!subject.hasRole("administrator")) {
        throw new AuthorizationException(...);
    }
    
    //Subject is guaranteed to be an 'administrator' here
    ...
}

案例五(记住用户验证):

@RequiresUser
public void updateAccount(Account account) {
    //this method will only be invoked by a 'user'
    //i.e. a Subject with a known identity
    ...
}

    等同于

public void updateAccount(Account account) {
    Subject currentUser = SecurityUtils.getSubject();
    PrincipalCollection principals = currentUser.getPrincipals();
    if (principals == null || principals.isEmpty()) {
        //no identity - they're anonymous, not allowed:
        throw new AuthorizationException(...);
    }
    
    //Subject is guaranteed to have a known identity here
    ...
}


Authorization的内部实现



1.subject的验证检测方法接收参数;

2.交由securityManager内部实现的 org.apache.shiro.authz.Authorizer接口的检验验证方法进行验证;

3.Authorizer调用默认的 ModularRealmAuthorizer进行验证检测;

4.配置中的Relam都检查自己是否实现自Authorizer接口,如果是则启动进行验证检测。

(如果配置中Relam匹配Authorizer,一方面,如果Relam处理抛出异常,则继续其他授权及验证;另一方面,如果Relam处理返回TRUE,则验证通过。如果Relam不匹配Authorizer,则不处理。)


设置全局PermissionResolver(转换String权限标识为Permission对象),可以进行自定义设置(shiro.ini)

globalPermissionResolver = com.foo.bar.authz.MyPermissionResolver
...
securityManager.authorizer.permissionResolver = $globalPermissionResolver
...

    每个接收配置中PermissionResolver的Relam都需要实现PermisionResolverAware接口。

    为了避免多次实现PermissionResolverAware接口,可以直接配置一个特定的Relam:

permissionResolver = com.foo.bar.authz.MyPermissionResolver

realm = com.foo.bar.realm.MyCustomRealm
realm.permissionResolver = $permissionResolver
...


设置全局RolePermissionResolver(转换String的角色名为一个实体对象),可以自定义配置(shiro.ini)

globalRolePermissionResolver = com.foo.bar.authz.MyPermissionResolver
...
securityManager.authorizer.rolePermissionResolver = $globalRolePermissionResolver
...

    每个接收配置中RolePermissionResolver的Relam都需要实现RolePermissionResolverAware接口。

    为了避免多次实现RolePermissionResolverAware接口,可以直接配置一个特定的Relam:

rolePermissionResolver = com.foo.bar.authz.MyRolePermissionResolver

realm = com.foo.bar.realm.MyCustomRealm
realm.rolePermissionResolver = $rolePermissionResolver
...


如果应用中授权的Relam多于一个,则默认的ModularRealmAuthorizer的简单型短路迭代机制就不实用了,需要自己定义更为强大的Authorizer(shiro.ini)

[main]
...
authorizer = com.foo.bar.authz.CustomAuthorizer

securityManager.authorizer = $authorizer



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值