需求:
|---前一个的程序通过shiro-permission.ini作为数据源对权限信息进行静态配置,实际开发中从数据库中获取权限数据
就需要自定义realm,由Realm从数据库查询权限数据。
|---Realm根据用户身份查询权限数据,将权限数据返回给Authorizer(授权器)
|
|---自定义Realm【实现AuthorizingRealm】
|---在原来自定义的Realm中修改doGetAuthorizationInfo
配置shiro-realm.ini文件【跟上面一样,配置realm到securityManager中】
[main]
#自定义realm
customRealm = cn.marer.shiro.realm.CustomRealm
#将realm设置到securityManager,相当于Spring中的注入
securityManager.realms = $customRealm
此文老猫原创,转载请加本文连接:http://blog.csdn.net/nthack5730/article/details/51019516
更多有关老猫的文章:http://blog.csdn.net/nthack5730
自定义Realm测试:
|---需要注意的是:下面方法中部分代码代替了数据库的查询过程
|---重写实现方法:doGetAuthorizationInfo(PrincipalCollection principals)
import java.util.ArrayList;
import java.util.List;
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;
/**
* 自定义Realm
* @author CatScan
*
*/
public class CustomRealm extends AuthorizingRealm{
final String realmName="customRealm";
//设置realmName
@Override
public void setName(String name) {
super.setName(realmName);
}
//用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// 第一步从token中取出用户发送过来的身份信息
String userCode = (String) token.getPrincipal();
//第二步根据用户输入的帐号从数据库查询
//...
String pwd = "11111";
//如果查询不到返回null
//如果查询到,返回认证信息:AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userCode, pwd, this.getName());
return simpleAuthenticationInfo;
}
//用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//从principals获取主身份信息
//将getPrimaryPrincipal()返回的值强制转换为真实身份信息【在上边的doGetAuthenticationInfo()认证通过填充到SimpleAuthenticationInfo中的身份信息】
String userCode = (String) principals.getPrimaryPrincipal();
//根据身份信息获取权限信息
//先链接数据库。。。
//模拟从数据库获取数据
List<String> permissions = new ArrayList<String>();
permissions.add("user:create");//用户的创建权限
permissions.add("user:update");//用户的修改
permissions.add("item:add");//商品的添加权限
//....等等权限
//查到权限数据,返回
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//将List里面的权限填充进去
simpleAuthorizationInfo.addStringPermissions(permissions);
return simpleAuthorizationInfo;
}
}
此文老猫原创,转载请加本文连接:http://blog.csdn.net/nthack5730/article/details/51019516
更多有关老猫的文章:http://blog.csdn.net/nthack5730
测试类:测试自定义Realm授权功能
|---主要是要注意好是否已经在上面的配置文件中绑定了测试的Realm
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;
public class AuthorizationTest {
//===========================================
// 自定义Realm进行授权测试:角色授权、资源授权
//===========================================
@Test
public void testAuthorizationCustomRealm(){
//创建一个SecurityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
//创建SecurityManager
SecurityManager sm = factory.getInstance();
//将SecurityManager设置到系统运行环境,和Spring整合后将SecurityManager配置到Spring容器中,一般单例管理
SecurityUtils.setSecurityManager(sm);
//创建Subject
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "11111");
//执行认证
try {
subject.login(token);
} catch (AuthenticationException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("认证状态:" + subject.isAuthenticated());
//认证通过后执行授权
//===========================================
// 基于角色授权
//===========================================
//hasRole方法传入的是角色标识
// boolean isHasRole = subject.hasRole("role1");
// System.out.println("正确角色,角色有权限--->" + isHasRole);
// //传入错误的角色
// boolean isHasRole2 = subject.hasRole("role12");
// System.out.println("错误角色,角色有权限--->" + isHasRole2);
// //判断多个角色
// boolean hasAllRoles = subject.hasAllRoles(Arrays.asList("role1","role2"));
// System.out.println("多个角色判断--->" + hasAllRoles);
//使用check方法进行授权,如果不通过,会抛出异常
// try {
// subject.checkRole("role12");
// } catch (AuthorizationException e) {
// // TODO 自动生成的 catch 块
// e.printStackTrace();
// }
//===========================================
// 基于资源授权
//===========================================
//调用isPermitted(),就会调用CustomRealm从数据库查数据权限数据
//isPermitted()传入权限标识符,判断user:create:1是否在CustomRealm查询到权限数据之内
boolean isPermited = subject.isPermitted("user:create:1");
System.out.println("资源有权限,单个权限判断--->" + isPermited);
//传入的是资源标识符,多个权限判断
boolean isPermitedAll = subject.isPermittedAll("user:create","user:update","user:delete");
System.out.println("资源有权限,多个权限判断--->" + isPermitedAll);
//资源权限也支持check,如果不通过,也会抛异常
try {
subject.checkPermission("item:add");
} catch (AuthorizationException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println(e.toString());
}
subject.getPrincipal();
}//method
}
授权的流程的总结:
- subject进行授权,调用方法:isPermitted("permission串");或isAllPermitted();【查看permission串在不在权限范围内】
- 由SecurityManager执行授权,最终通过ModularRealmAuthorizer执行授权
- ModularRealmAuthorizer执行Realm【上面自定义的CustomRealm】从数据库查询权限数据
- 【调用Realm的:doGetAuthorizationInfo(PrincipalCollection principals) 】
- Realm从数据库查询权限数据,返回ModularRealmAuthorizer【这个词和认证的方法容易混淆,记得注意区分】
- ModularRealmAuthorizer进行权限数据的匹配:调用PermissionResolver进行权限比对。
- 如果比对后:isPermitted(中的"permission串"),在Realm查询到的权限数据中,说明授权通过【用户访问的Permission串具有权限;否则,没有权限,抛出异常】
此文老猫原创,转载请加本文连接:http://blog.csdn.net/nthack5730/article/details/51019516
更多有关老猫的文章:http://blog.csdn.net/nthack5730