一、Realm:
1、介绍:在Shiro中,Realm是一个非常灵活和强大的安全组件,它能够与各种数据源进行集成,满足各种安全需求。通过实现自定义的Realm,可以轻松地定制身份验证、授权和加密逻辑,实现更加细粒度的访问控制。
2、作用:Realm主要作用是身份验证和授权。当一个Subject需要进行身份验证时,它会调用SecurityManager中的authenticate方法,该方法会委托给所有配置的Realm来进行身份验证。当验证成功后,Realm会返回一个SimpleAuthenticationInfo对象,其中包含了身份验证信息(如用户名、密码等),这些信息会在会话管理中使用。Realm还可以用于加密和解密操作。例如,使用Realm中的CredentialsMatcher
接口可以对密码进行加密和验证。
3、扩展:Shiro提供了多个默认的Realm实现,包括:
(1)IniRealm:通过一个INI配置文件来存储用户、角色和权限信息。
(2)JdbcRealm:通过JDBC来访问数据库,存储用户、角色和权限信息。
(3)ActiveDirectoryRealm:通过LDAP协议来访问Active Directory,存储用户、角色和权限信息。
(4)LdapRealm:通过LDAP协议来访问LDAP服务器,存储用户、角色和权限信息。
(5)TextConfigurationRealm:通过一个文本文件来存储用户、角色和权限信息。
(6)也可以通过继承AbstractAuthorizingRealm或AbstractAuthenticatingRealm来创建自定义的Realm实现。
(7)AuthorizingRealm:实际使用一般继承这种即可。
4、Realm的使用:在使用Realm时,需要将其配置到SecurityManager中,有两种方法:
(1)配置文件方法:shiro提供ini配置文件,进行IOC容器管理,当然可以配置realm
[main]
securityManager.realms = $iniRealm, $jdbcRealm
[iniRealm]
# IniRealm的配置
[jdbcRealm]
# JdbcRealm的配置
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
JdbcRealm jdbcRealm = new JdbcRealm();
securityManager.setRealms(Arrays.asList(iniRealm, jdbcRealm));
(2)编程方式:
CustomRealm customRealm = new CustomRealm();
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(securityManager);
二、AuthenticationToken:
1、作用:用于收集用户提交的身份(如用户名)及凭据(如密码):
public interface AuthenticationToken extends Serializable {
Object getPrincipal();
Object getCredentials();
}
2、扩展接口/实现类:
(1)RememberMeAuthenticationToken接口提供了boolean isRememberMe()功能;
(2)HostAuthenticationToken接口提供了String getHost();获取用户主机的功能
(3)UsernamePasswordToken:
public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken
三、AuthenticationInfo:
1、介绍:表示Subject
存储的只和鉴权/登录过程相关的账户信息;和AuthenticationToken、AuthorizationInfo的比较:
(1)AuthenticationToken表示登录时提交的凭据信息(可能匹配,也可能不匹配AuthenticationInfo
);
(2)AuthenticationInfo
表示已经验证过且存储在系统中的账户信息;
(3)AuthorizationInfo
表示访问控制数据,如角色和权限;
2、核心方法:
public interface AuthenticationInfo extends Serializable {
PrincipalCollection getPrincipals();
Object getCredentials();
}
3、实现子类:
public interface AuthenticationInfo extends Serializable
public interface Account extends AuthenticationInfo, AuthorizationInfo
public class SimpleAccount implements Account, MergableAuthenticationInfo, SaltedAuthenticationInfo, Serializable
public interface MergableAuthenticationInfo extends AuthenticationInfo
public class SimpleAccount implements Account, MergableAuthenticationInfo, SaltedAuthenticationInfo, Serializable
public class SimpleAuthenticationInfo implements MergableAuthenticationInfo, SaltedAuthenticationInfo
public interface SaltedAuthenticationInfo extends AuthenticationInfo
public class SimpleAccount implements Account, MergableAuthenticationInfo, SaltedAuthenticationInfo, Serializable
public class SimpleAuthenticationInfo implements MergableAuthenticationInfo, SaltedAuthenticationInfo
(1)Account:同时继承AuthenticationInfo
和AuthorizationInfo
接口,表示单个Realm
中单个账户的鉴权和授权;
(2)MergableAuthenticationInfo:支持合并其它AuthenticationInfo
的实现,即允许本类实例是来自多个Realm
的账户数据的聚合或者组合;支持多Realm
鉴权;
(3)SaltedAuthenticationInfo:表示支持使用盐值进行哈希凭据信息的账户信息,主要为了支持需要哈希用户凭据的环境;盐值通常从安全的伪随机数生成器生成,和账户信息一起安全地存储,和账户的凭据一起维护;
(4)SimpleAuthenticationInfo:MergableAuthenticationInfo
的简单实现;一般情况使用这种即可。
(5)SimpleAccount:Account
的简单实现,内部使用SimpleAuthenticationInfo
和SimpleAuthorizationInfo
实例实现Account
接口;
四、PrincipalCollection:
shiro可以同时配置多个realm,所以身份信息可能就有多个,因此提供了PrincipalCollection用于聚合这些身份信息。
public interface PrincipalCollection extends Iterable, Serializable {
Object getPrimaryPrincipal();
<T> T oneByType(Class<T> var1);
<T> Collection<T> byType(Class<T> var1);
List asList();
Set asSet();
Collection fromRealm(String var1);
Set<String> getRealmNames();
boolean isEmpty();
}
在Realm中,PrincipalCollection.getPrimaryPrincipal()得到的类型即为doGetAuthenticationInfo身份认证接口设置返回的principals身份类型,可能是字符串(用户名),也可能是对象(用户对象)。
五、AuthorizationInfo:
1、作用:用于聚合授权信息:
public interface AuthorizationInfo extends Serializable {
Collection<String> getRoles();
Collection<String> getStringPermissions();
Collection<Permission> getObjectPermissions();
}
在使用AuthorizingRealm时,如果身份验证成功,在授权时就通过doGetAuthorizationInfo方法获取角色/权限信息用于授权验证。
2、使用:大多数时候使用SimpleAuthorizationInfo即可。
六、Subject:
1、介绍:是Shiro的认证授权组件 提供当前用户信息(角色 授权),然后进行登录、退出、权限验证等,我们常将一个Subject对象称之为一个用户。
2、获取Subject:使用SecurityUtils.getSubject()可以获得当前的Subject。
3、主要接口/作用:
(1)获取身份信息
Object getPrincipal();
PrincipalCollection getPrincipals();
(2)身份验证:
void login(AuthenticationToken var1) throws AuthenticationException;
boolean isAuthenticated();
boolean isRemembered();
(3)授权验证:
boolean isPermitted(String var1);
boolean isPermitted(Permission var1);
boolean[] isPermitted(String... var1);
boolean[] isPermitted(List<Permission> var1);
boolean isPermittedAll(String... var1);
boolean isPermittedAll(Collection<Permission> var1);
void checkPermission(String var1) throws AuthorizationException;
void checkPermission(Permission var1) throws AuthorizationException;
void checkPermissions(String... var1) throws AuthorizationException;
void checkPermissions(Collection<Permission> var1) throws AuthorizationException;
boolean hasRole(String var1);
boolean[] hasRoles(List<String> var1);
boolean hasAllRoles(Collection<String> var1);
void checkRole(String var1) throws AuthorizationException;
void checkRoles(Collection<String> var1) throws AuthorizationException;
void checkRoles(String... var1) throws AuthorizationException;
(4)会话:
Session getSession();//相当于getSession(true)
Session getSession(boolean var1);
(5)退出:
void logout();
(6)Run As
void runAs(PrincipalCollection var1) throws NullPointerException, IllegalStateException;
boolean isRunAs();
PrincipalCollection getPreviousPrincipals();
PrincipalCollection releaseRunAs();
(7)多线程
<V> V execute(Callable<V> var1) throws ExecutionException;
void execute(Runnable var1);
<V> Callable<V> associateWith(Callable<V> var1);
Runnable associateWith(Runnable var1);
六、SecurityUtils:是 Shiro 中一个抽象类。并且没有任何子类。其中声明了一个静态属性,三个静态方法。
//一个静态属性,用来存储当前应用中全局唯一的一个SecurityManager。
private static SecurityManager securityManager;
//静态方法
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
}