Spring-shiro-Boot-9 shiro权限的原理与数据结构

本文介绍了Shiro授权的原理,包括主体(Subject)、资源(Resource)、权限(Permission)和角色(Role)。详细讲解了Shiro授权的三种方式:编程式、注解式和标签式,并着重阐述了注解的使用,如@RequiresAuthentication、@RequiresUser、@RequiresGuest、@RequiresPermissions和@RequiresRoles。此外,还讨论了AuthorizationInfo模型体系和Realm中doGetAuthorizationInfo方法的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

授权:也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。

shiro中,主要有主体(Subject)、资源(Resource)、权限(Permission)、 角色(Role)。

一、shiro中的授权方式

(1)编程式

Subject subject = SecurityUtils.getSubject(); 
if(subject.hasRole(“admin”)) 
{ //有权限 } 
else 
{ //无权限 }

(2)注解式

@RequiresRoles("admin") 
public void hello() 
{ //有权限 }

(3)标签式

<shiro:hasRole name="admin"> 
<!— 有权限—> 
</shiro:hasRole>

二、shiro中授权的注解

(1)@RequiresAuthentication

要求当前Subject已经在session中验证通过(验证当前用户是否登录:subject.isAuthenticated() 结果为true)

(2)@RequiresUser

验证用户是否被记忆,user有两种含义:

1) 一种是成功登录的(subject.isAuthenticated() 结果为true);

2) 另外一种是被记忆的(subject.isRemembered()结果为true)。

(3)@RequiresGuest

用户没有登录认证或被记住过,验证是否是一个guest的请求,与@RequiresUser完全相反。换言之,RequiresUser == !RequiresGuest。此时subject.getPrincipal() 结果为null.

(4)@RequiresPermissions

验证用户是否具有一个或多个权限,该注解将会经常在项目中使用,如果不满足条件则抛出AuthorizationException异常

1) 是否具有某一权限@RequiresPermission("account:create")

2) 是否具有多个权限@RequiresPermission({"account:create","account:update"})

(5)@RequiresRoles

验证当前用户是否具有某角色,与验证权限类似

三、授权原理

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

四、AuthorizationInfo模型体系

 

 AuthorizationInfo是授权信息的数据模型。


public interface AuthorizationInfo extends Serializable {
	Collection<String> getRoles(); //获取角色字符串信息
	Collection<String> getStringPermissions(); //获取权限字符串信息
	Collection<Permission> getObjectPermissions(); //获取Permission对象信息
}

具体实现类分析:

(1)SimpleAuthorizationInfo

AuthorizationInfo的简单实现,具体来说其内部使用Set存储角色名称、权限字符串、权限; 

protected Set<String> roles;
protected Set<String> stringPermissions;
protected Set<Permission> objectPermissions;

(2)Account

同时继承AuthenticationInfoAuthorizationInfo接口;表示单个Realm中单个账户的鉴权和授权;

(3)SimpleAccount

 Account接口的具体实现。比较简单,直接上源码:

// 鉴权信息,实现AuthenticationInfo接口
private SimpleAuthenticationInfo authcInfo;
// 授权信息,实现AuthorizationInfo接口
private SimpleAuthorizationInfo authzInfo;
// 账户锁定标识
private boolean locked;
// 账户过期标识
private boolean credentialsExpired;

/**
 * 构造方法
 */
public SimpleAccount(PrincipalCollection principals, Object credentials) {
    // 鉴权信息
    this.authcInfo = new SimpleAuthenticationInfo(principals, credentials);
    // 授权信息
    this.authzInfo = new SimpleAuthorizationInfo();
}

/**
 * 获取锁定标识
 */
public boolean isLocked() {
    return locked;
}

/**
 * 设置锁定标识
 */
public void setLocked(boolean locked) {
    this.locked = locked;
}

/**
 * 获取过期标识
 */
public boolean isCredentialsExpired() {
    return credentialsExpired;
}

/**
 * 设置过期标识
 */
public void setCredentialsExpired(boolean credentialsExpired) {
    this.credentialsExpired = credentialsExpired;
}

public void merge(AuthenticationInfo info) {
    // 合并鉴权信息
    authcInfo.merge(info);

    // Merge SimpleAccount specific info
    if (info instanceof SimpleAccount) {
        // 合并SimpleAccount的锁定和过期标识
        SimpleAccount otherAccount = (SimpleAccount) info;
        if (otherAccount.isLocked()) {
            setLocked(true);
        }

        if (otherAccount.isCredentialsExpired()) {
            setCredentialsExpired(true);
        }
    }
}

五、Realm实现:doGetAuthorizationInfo方法

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		log.debug("权限配置");

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		User user = UserUtil.getCurrentUser();
		//获取当前用户对应的角色ids
		List<Role> roles = SpringUtil.getBean(RoleDao.class).listByUserId(user.getId());
		//获取当前用户对应的角色names
		Set<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toSet());
		//一、authorizationInfo设置角色
		authorizationInfo.setRoles(roleNames);
		//获取当前用户对应的权限permissions
		List<Permission> permissionList = SpringUtil.getBean(PermissionDao.class).listByUserId(user.getId());
		//为当前用户设置权限,放到session中
		UserUtil.setPermissionSession(permissionList);
		Set<String> permissions = permissionList.stream().filter(p -> !StringUtils.isEmpty(p.getPermission()))
				.map(Permission::getPermission).collect(Collectors.toSet());
		//二、authorizationInfo设置权限
		authorizationInfo.setStringPermissions(permissions);

		return authorizationInfo;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良之才-小良

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值