Shiro框架:授权流程、授权方式、Shiro授权入门程序、自定义Realm进行授权

一、Shiro授权:

1、授权与权限:

(1)授权:访问控制,必须具有该资源的访问权限才可以访问该资源。

(2)权限模型:标准权限数据模型包括 :用户、角色、权限(包括资源和权限)、用户角色关系、角色权限关系。

(3)权限分配:通过UI界面方便给用户分配权限,对上边权限模型进行增、删、改、查操作。

(4)权限控制:

第一种:基于角色的权限控制:根据角色判断是否有操作权限,因为角色的变化性较高,如果角色修改需要修改控制代码,系统可扩展性不强。

第二种:基于资源的权限控制:根据资源权限判断是否有操作权限,因为资源较为固定,如果角色修改或角色中权限修改不需要修改控制代码,使用此方法系统可维护性很强。建议使用。

(5)权限管理的解决方案:

①对于粗颗粒权限管理,建议在系统架构层面去解决,写系统架构级别统一代码(基础代码)。

粗颗粒权限:比如对系统的url、菜单、jsp页面、页面上按钮、类方法进行权限管理,即对资源类型进行权限管理。

②对于细颗粒权限管理:细颗粒权限管理是系统的业务逻辑,业务逻辑代码不方便抽取统一代码,建议在系统业务层进行处理。

粗颗粒权限:比如用户id为001的用户信息(资源实例)、类型为t01的商品信息(资源实例),对资源实例进行权限管理,可以理解为对数据级别的权限管理。

 

2、授权流程:

(1)对subject进行授权,调用方法isPermitted("permission串");

(2)SecurityManager执行授权,通过ModularRealmAuthorizer执行授权;

(3)ModularRealmAuthorizer执行realm(自定义的CustomRealm)从数据库查询权限数据,调用realm的授权方法:doGetAuthorizationInfo;

(4)realm从数据库查询权限数据,返回ModularRealmAuthorizer;

(5)ModularRealmAuthorizer调用PermissionResolver进行权限串比对;

(6)如果比对后,isPermitted中"permission串"在realm查询到权限数据中,说明用户访问permission串有权限,否则 没有权限,抛出异常。

3、Shiro 支持三种方式的授权:

(1)编程式:通过写if/else 授权代码块完成:

Subject subject = SecurityUtils.getSubject();

if(subject.hasRole(“admin”)) {

//有权限

} else {

//无权限

}

(2)注解式:通过在执行的Java方法上放置相应的注解完成:

@RequiresRoles("admin")

public void hello() {

//有权限

}

(3)JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:

<shiro:hasRole name="admin">

<!— 有权限—>

</shiro:hasRole>

二、Shiro授权示例程序:

1、入门的Shiro授权程序:

(1)编写shiro-permission.ini文件:

shiro-permission.ini文件里边的内容相当于在数据库查询出来的;

#用户
[users]
#用户zhangsan的密码是123,此用户具有role1和role2两个角色
zhangsan=123456,role1,role2
wangwu=123456,role2

#权限
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
role2=user:create,items:delete
role3=user:create

权限标识符号规则:资源:操作:实例(中间使用半角:分隔)

user:create:01  表示对用户资源的01实例进行create操作。

user:create    表示对用户资源进行create操作,相当于user:create:*,对所有用户资源实例进行create操作。

user:*:01  表示对用户资源实例01进行所有操作。

(2)程序编写:

//shiro的授权测试:
public class AuthorizationTest {

	//角色授权、资源授权测试:
	@Test
	public void testAuthorization(){
		Factory<SecurityManager> factory = new IniSecurityManagerFactory(
				"classpath:shiro-permission.ini");
		SecurityManager securityManager = factory.getInstance();
		SecurityUtils.setSecurityManager(securityManager);
		SecurityUtils.setSecurityManager(securityManager);
		Subject subject = SecurityUtils.getSubject();
	
		UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
				"123456");
		try {
			subject.login(token);
		} catch (AuthenticationException e) {
			e.printStackTrace();
		}
		System.out.println("认证状态:" + subject.isAuthenticated());
		
		//认证通过之后执行授权:
		
		//基于角色的授权
		//hasRole传入角色标识:
		boolean ishasRole = subject.hasRole("role1");
		System.out.println("单个角色判断" + ishasRole);
		//hasAllRoles是否拥有多个角色:
		boolean hasAllRoles = subject.hasAllRoles(Arrays.asList("role1","role2","role3"));
		System.out.println("多个角色判断" + hasAllRoles);
		// 使用check方法进行授权,如果授权不通过会抛出异常
		subject.checkRole("role2");
		
		//基于资源的授权:
		//isPermitted传入权限标识符
		boolean isPermitted = subject.isPermitted("user:create:1");
		System.out.println("单个权限判断" + isPermitted);

		boolean isPermittedAll = subject.isPermittedAll("user:create:1",
				"user:delete");
		System.out.println("多个权限判断" + isPermittedAll);
		
		// 使用check方法进行授权,如果授权不通过会抛出异常
		subject.checkPermission("items:delete:1");
	}
}

(3)执行结果:

至此,Shiro授权入门程序就完成了。在这个程序中,我们读取的是在shiro.ini配置文件中静态配置好的权限内容,但是在实际开发,我们通常是从数据库中查询用户所拥有的权限信息,因此,我们需要使用自定义的Realm进行从数据库中查询用户的权限信息。

 

2、自定义realm进行授权:

上面的程序是通过shiro-permission.ini对权限文件进行静态配置,在实际开发中,都是从数据库中获取权限数据。就需要自定义realm,由realm从数据库查询权限数据。

realm根据用户身份查询权限数据,将权限数据返回给authorizer(授权器)。

(1)自定义realm:

//自定义的Realm,需要继承AuthorizingRealm,并且重写这个类的两个方法
public class CustomRealm extends AuthorizingRealm{
	// 设置realm的名称
	@Override
	public void setName(String name) {
		super.setName("customRealm");
	}

	// 用于授权
	@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("items:add");//商品添加权限
		
		//查到权限数据,返回授权信息(要包括上边的permissions)
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		//将上边查询到授权信息填充到simpleAuthorizationInfo对象中
		simpleAuthorizationInfo.addStringPermissions(permissions);
		return simpleAuthorizationInfo;
	}
}

(2)编写shiro-realm.ini文件:

在shiro-realm.ini文件中配置自定义的realm,将realm设置到securityManager中。

[main]
#自定义的realm
customRealm=com.zwp.shiro.realm.CustomRealm
#将realm设置到securityManager,相当于spring中的注入
securityManager.realms=$customRealm

(3)测试:

	// 自定义realm进行资源授权测试
	@Test
	public void testAuthorizationCustomRealm() {

		Factory<SecurityManager> factory = new IniSecurityManagerFactory(
				"classpath:shiro-realm.ini");
		SecurityManager securityManager = factory.getInstance();
		SecurityUtils.setSecurityManager(securityManager);
		Subject subject = SecurityUtils.getSubject();

		// 创建token令牌
		UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
				"123456");
		// 执行认证
		try {
			subject.login(token);
		} catch (AuthenticationException e) {
			e.printStackTrace();
		}
		System.out.println("认证状态:" + subject.isAuthenticated());
		
		// 认证通过后执行授权
		// 基于资源的授权,调用isPermitted方法会调用CustomRealm从数据库查询正确权限数据
		// isPermitted传入权限标识符,判断user:create:1是否在CustomRealm查询到权限数据之内
		boolean isPermitted = subject.isPermitted("user:create:1");
		System.out.println("单个权限判断" + isPermitted);
		boolean isPermittedAll = subject.isPermittedAll("user:create:1",
				"user:create");
		System.out.println("多个权限判断" + isPermittedAll);

		// 使用check方法进行授权,如果授权不通过会抛出异常
		subject.checkPermission("items:add:1");
	}

(4)测试结果:

至此,Shiro使用自定义Realm进行授权的程序就完成了。

 

猜你喜欢

转载自blog.csdn.net/a745233700/article/details/81294056