Shiro(3)-授权

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作
等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

关键对象介绍

主体
主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。
资源
在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
权限
安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的
权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)打印文档等等。。。
角色
角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权
限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

授权流程

Shiro(3)-授权

流程如下:

1、首先调用Subject.isPermitted*/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;
2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer 进行循环判断,如果匹配如isPermitted
/hasRole*会返回true,否则返回false表示授权失败。

授权方式

Shiro 支持三种方式的授权

//编程式:通过写if/else 授权代码块完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
//注解式:通过在执行的Java方法上放置相应的注解完成:
//没有权限将抛出相应的异常;
@RequiresRoles("admin")
public void hello() {
//有权限
}
JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!— 有权限—>
</shiro:hasRole>

授权实现

在ini配置文件配置用户拥有的角色及角色-权限关系

[users]
root=123,role1,role2

[roles]
role1 = user:add,user:delete
role2 = user:list

规则:“用户名=密码,角色1,角色2” “角色=权限1,权限2”,即首先根据用户名找到角色,然后根据角色再找到权限;即角色是权限集合;Shiro 同样不进行权限的维护,需要我们通过Realm返回相应的权限信息。只需要维护“用户——角色”之间的关系即可。

public static void main(String[] args) {
	
	Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro03");
	SecurityManager securityManager = factory.getInstance();
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("root","123");
	try {
	    subject.login(token);
	    System.out.println("成功登陆");
	    
	} catch (Exception e) {
	    System.out.println("登陆失败");
	}
	//检测是否拥有role1角色
	if(subject.hasRole("role1")){
	    System.out.println("拥有role1的角色");
	}
	//基于资源的授权
	if(subject.isPermitted("user:add")){
	    System.out.println("拥有user:add的权限");
	}
	//判断用户是否拥有权限,如果没有抛出异常
	subject.checkPermission("user:list");
    }

自定义Realm实现授权

public class UserRealm3 extends AuthorizingRealm {

    /**
     * @Description:授权信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
	    PrincipalCollection principals) {
	
	//获取用户名
	String username = principals.getPrimaryPrincipal().toString();
	//根据用户名查询权限信息
	List<String> permission = new ArrayList<String>();
	System.out.println("获取权限");
	//模拟从数据库获取权限
	permission.add("user:add");
	permission.add("user:delete");
	//将权限封装到SimpleAuthorizationInfo中
	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	info.addStringPermissions(permission);
	return info;
    }

    /**
     * @Description:身份认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
	    AuthenticationToken token) throws AuthenticationException {
	//获取用户输入的用户名
	String username = (String) token.getPrincipal();
	System.out.println("验证用户信息");
	//从数据库获取密码
	String password = "123";
	//将用户信息封装到SimpleAuthenticationInfo
	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
	
	return info;
    }
}
[main]
userRealm = com.QEcode.realm.UserRealm3
securityManager.realm=$userRealm

[users]
root=123
public static void main(String[] args) {
	Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro04.ini");
	SecurityManager securityManager = factory.getInstance();
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("root","123");
	try {
	    subject.login(token);
	    if(subject.isAuthenticated()){
		System.out.println("验证通过");
	    }
	} catch (AuthenticationException e) {
	    e.printStackTrace();
	    System.out.println("验证失败");
	}
	//验证是否拥有权限
	System.out.println(subject.isPermittedAll("user:add","user:delete"));
    }