你是谁,你是谁决定了你的身份是什么,你的身份决定了你能干什么。
这里牵扯出三种对象。
用户对象user:当前操作的用户。
角色对象role :表示一组 "权限操作许可权" 的集合。
权限对象permission:资源操作许可权。
例如,大宇(user)需要下载(permission)一个高清无码的种子,需要VIP权限(role)。所以,本次下载大致流程是先判断大宇是不是vip,然后再查看vip这种角色有没有下载权限。
首先必须强调的是:进行授权操作的前提:用户必须通过认证。
在真实的项目中,角色与权限都存放在数据库中。为了快速上手,我们先创建一个自定义Realm,模拟它已经登录成功。直接返回一个登录验证凭证,告诉Shiro框架,我们从数据库中查询出来的密码是也是就是你输入的密码。所以,不管用户输入什么,本次登录验证都是通过的。
package shiro;
public class PermissionRealm extends AuthorizingRealm ...
//认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String yourInputUsername = (String) token.getPrincipal();
String yourInputPassword = new String((char[]) token.getCredentials());
//默认要被验证的密码就是用户输入的密码,所以用户输入什么密码都是对的
String passwordFromDB = yourInputPassword;
return new SimpleAuthenticationInfo(yourInputUsername, passwordFromDB, getName());
}
好了,接下来,我们要重写我们本小节的核心方法了。此方法的方法签名是:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
此方法的传入的参数PrincipalCollection principals,是一个包装对象,它表示"用户认证凭证信息"。包装的是谁呢?没错,就是认证doGetAuthenticationInfo()方法的返回值的第一个参数yourInputUsername。你可以通过这个包装对象的getPrimaryPrincipal()方法拿到此值。就像下面的代码展示的那样。
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String yourInputUsername = (String) principals.getPrimaryPrincipal();
return null;
}
既然在Realm中获取到了你的用户名,即登录凭证,那么下一步显然就是去数据库中查询你这个人是什么角色,有什么样的权限。假设你是一线开发人员,你对于公司代码所拥有的权限有:增加code:insert、修改code:update。用下面代码展示一下上述的论述。
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String yourInputUsername = (String) principals.getPrimaryPrincipal();
//构造一个授权凭证
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//通过你的用户名查询数据库,得到你的权限信息与角色信息。并存放到权限凭证中
info.addRole(getYourRoleByUsernameFromDB(yourInputUsername));
info.addStringPermissions(getYourPermissionByUsernameFromDB(yourInputUsername));
//返回你的权限信息
return info;
}
private String getYourRoleByUsernameFromDB(String username) {
return "coder";
}
private List getYourPermissionByUsernameFromDB(String username) {
return Arrays.asList("code:insert", "code:update");
}
OK,现在,你的权限信息已经被Shiro框架知晓了。下面我们就来使用Shiro的相关API来验证你的权限信息。
Subject这个门面又出现了!没错,几乎所有的Shiro框架的入口,都是这个门面对象。
第一步,先把我们的Realm配置到shiro.ini配置文件中。以后将不会使用这个shiro.ini文件,实际项目中会把shiro的相关配置使用Spring的配置文件集成。不过,你现在还不必关心那种配置方式,等到了与Spring集成的时候再说。
#shiro.ini 配置文件
[main]
#等号右边的shiro.PermissionRealm是包名+类名
myRealm=shiro.PermissionRealm
securityManager.realms=$myRealm
Shiro的Subject门面为我们提供了两套验证角色与权限的API接口。一组是以has开头的,它返回Boolean类型,如果你有此权限,那么返回true,反之返回false。另外一组是以check开头的,无任何返回值。它在检查你的角色信息或者权限信息的时候,如果你有此权限或者角色信息,它将不做任何操作,反之,则抛出一个异常,以中断当前程序的运行。
OK,知道了如何检查角色或者权限信息,让我们开始编写代码吧。
@Test
public void testPermissionRealm() {
Subject subject = login("anyUsername", "anyPassword");
//使用断言判断用户是否已经登录
Assert.assertTrue(subject.isAuthenticated());
//---------登录结束------------
//---------检查当前用户的角色信息------------
System.out.println(subject.hasRole("coder"));
//---------如果当前用户有此角色,无返回值。若没有此权限,则抛 UnauthorizedException------------
subject.checkRole("coder");
//---------检查当前用户的权限信息------------
System.out.println(subject.isPermitted("code:insert"));
//---------如果当前用户有此权限,无返回值。若没有此权限,则抛 UnauthorizedException------------
subject.checkPermissions("code:insert", "code:update");
}
private Subject login(String yourInputUsername, String yourInputPassword) {
//读取配置文件
Factory factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token =
new UsernamePasswordToken(yourInputUsername, yourInputPassword);
//调用自定义Realm的doGetAuthenticationInfo方法进行认证操作
subject.login(token);
//返回当前shiro环境的门面
return subject;
}
package shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.Arrays;
import java.util.List;
/**
* @author jay.zhou
* @date 2018/12/22
* @time 13:53
*/
public class PermissionRealm extends AuthorizingRealm {
//认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String yourInputUsername = (String) token.getPrincipal();
String yourInputPassword = new String((char[]) token.getCredentials());
//默认要被验证的密码就是用户输入的密码,所以用户输入什么密码都是对的
String passwordFromDB = yourInputPassword;
return new SimpleAuthenticationInfo(yourInputUsername, passwordFromDB, getName());
}
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String yourInputUsername = (String) principals.getPrimaryPrincipal();
//构造一个授权凭证
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//通过你的用户名查询数据库,得到你的权限信息与角色信息
info.addRole(getYourRoleByUsernameFromDB(yourInputUsername));
info.addStringPermissions(getYourPermissionByUsernameFromDB(yourInputUsername));
//返回你的权限信息
return info;
}
private String getYourRoleByUsernameFromDB(String username) {
return "coder";
}
private List getYourPermissionByUsernameFromDB(String username) {
return Arrays.asList("code:insert", "code:update");
}
}
运行结果:
本章节项目源码:点击我下载源码
----------------------------------------------------分割线-------------------------------------------------------
下一篇:第五节 授权过程源代码追踪
阅读更多:跟着大宇学Shiro目录贴