核心概念:Subject,SecurityManager 和 Realms
Shiro的体系结构具有三个主要概念-主题(Subject),安全管理器(SecurityManager)和领域(Realms)。
Subject
在保护应用程序安全时,可能要问自己最相关的问题是:“当前用户是谁?”或“是否允许当前用户执行X”?
在编写代码或设计用户界面时,我们通常会问自己以下问题:应用程序通常是基于用户案例构建的,并且您希望基于每个用户来表示(和保护)功能。
因此,我们考虑应用程序安全性的最自然方法是基于当前用户。
Shiro的API从根本上代表了这种思维方式。
“主题”一词是一个安全术语,基本上表示“当前正在执行的用户”。它只是不被称为“用户”,因为“用户”一词通常与人类相关联。
在安全领域中,“主题”一词可以表示一个人,但也可以指第三方进程,守护程序帐户或任何类似内容。它仅表示“当前正在与软件交互的事物”。
不过,对于大多数意图和目的,您都可以将其视为Shiro的“用户”概念。
您可以在代码中的任何位置轻松获取Shiro主题,如下面的清单1所示。
- List1
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
...
Subject currentUser = SecurityUtils.getSubject();
获取主题后,您可以立即访问当前用户想要使用Shiro进行的所有操作的90%,例如登录,注销,访问其会话,执行授权检查等等-但稍后会介绍更多 。
这里的关键是Shiro的API在很大程度上是直观的,因为它反映了开发人员在“每用户”安全控制中进行思考的自然趋势。
在代码中的任何地方访问主题也很容易,从而可以在需要的地方进行安全操作。
安全管理器
主题的“幕后”对应对象是SecurityManager。
主题代表当前用户的安全操作,而SecurityManager管理所有用户的安全操作。它是Shiro体系结构的核心,是一种“伞”对象,它引用了许多内部嵌套的安全组件,这些安全组件构成了一个对象图。但是,一旦配置了SecurityManager及其内部对象图,通常就不理会它,应用程序开发人员几乎将所有时间都花在Subject API上。
那么如何设置SecurityManager?
好吧,这取决于您的应用程序环境。
例如,Web应用程序通常将在web.xml中指定Shiro Servlet过滤器,这将设置SecurityManager实例。如果您运行的是独立应用程序,则需要以其他方式进行配置。但是有许多配置选项。
每个应用程序几乎总是只有一个SecurityManager实例。
它本质上是一个应用程序单例(尽管不必是静态单例)。像Shiro中的几乎所有内容一样,默认的SecurityManager实现是POJO,并且可以使用任何与POJO兼容的配置机制-常规Java代码,Spring XML,YAML,.properties和.ini文件等进行配置。基本上,任何能够实例化类的东西并且可以使用与JavaBeans兼容的调用方法。
为此,Shiro通过基于文本的INI配置提供了默认的“共母”解决方案。
INI易于阅读,易于使用,并且几乎不需要依赖项。您还将看到,通过简单地了解对象图导航,可以有效地使用INI来配置简单的对象图,例如SecurityManager。
请注意,Shiro还支持Spring XML配置和其他替代方案,但我们将在此处介绍INI。
下面的清单2中的示例显示了基于INI配置Shiro的最简单示例。
- List2 使用 INI 配置
[main]
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
cm.hashAlgorithm = SHA-512
cm.hashIterations = 1024
# Base64 encoding (less text):
cm.storedCredentialsHexEncoded = false
iniRealm.credentialsMatcher = $cm[users]
jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2
asmith = IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCB
在清单2中,我们看到了用于配置SecurityManager实例的INI配置示例。
INI分为两个部分:[main]和[users]。
[main]部分是配置SecurityManager对象和/或SecurityManager使用的任何对象(如领域)的地方。在此示例中,我们看到两个对象被配置:
cm对象,它是Shiro的HashedCredentialsMatcher类的实例。如您所见,cm实例的各种属性是通过“嵌套点”语法配置的,该语法由清单3所示的IniSecurityManagerFactory用来表示对象图导航和属性设置。
iniRealm对象,是SecurityManager用来表示以INI格式定义的用户帐户的组件。
在[用户]部分中,您可以指定用户帐户的静态列表-适用于简单的应用程序或测试时。
出于本简介的目的,理解每一部分的复杂性并不重要,而是要了解INI配置是配置Shiro的一种简单方法。
有关INI配置的更多详细信息,请参阅Shiro的文档。
- List3 加载配置文件
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.util.Factory;//1. Load the INI configuration
Factory<SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");//2. Create the SecurityManager
SecurityManager securityManager = factory.getInstance();//3. Make it accessible
SecurityUtils.setSecurityManager(securityManager);
在清单3中,在这个简单的示例中,我们看到了一个三步过程:
-
加载将配置SecurityManager及其组成组件的INI配置。
-
根据配置(使用代表工厂方法设计模式的Shiro的工厂概念)创建SecurityManager实例。
-
使SecurityManager单例可被应用程序访问。
在这个简单的示例中,我们将其设置为VM静态单例,但这通常不是必需的-您的应用程序配置机制可以确定是否需要使用静态内存。
Realms(领域)
Shiro中的第三个也是最后一个核心概念是领域。
领域充当Shiro与应用程序的安全数据之间的“桥梁”或“连接器”。
也就是说,当需要真正与安全性相关的数据(例如用户帐户)进行交互以执行身份验证(登录)和授权(访问控制)时,Shiro会从为一个应用程序配置的一个或多个Realms中查找其中的许多内容。
从这个意义上说,领域本质上是特定于安全性的DAO:它封装了数据源的连接详细信息,并根据需要使关联数据可用于Shiro。在配置Shiro时,您必须至少指定一个领域用于身份验证和/或授权。可以配置多个Realm,但至少需要一个。
Shiro提供了开箱即用的领域,可以连接到许多安全数据源(又名目录),例如LDAP,关系数据库(JDBC),文本配置源(例如INI和属性文件)等等。
如果默认的Realms不能满足您的需求,那么您可以插入自己的Realm实现以表示自定义数据源。
下面的清单4是配置Shiro(通过INI)以将LDAP目录用作应用程序的领域之一的示例。
- 清单4.示例领域配置
[main]
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com
ldapRealm.contextFactory.url = ldap://ldapHost:389
ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5
现在,我们已经了解了如何设置基本的Shiro环境,让我们讨论您作为开发人员如何使用该框架。