Shiro整合到Web应用

2019-04-20 16:05|来源: 网路

概述

虽然Apache Shiro的核心设计目标允许它用于保护任何基于JVM的应用程序(如命令行应用程序,服务器守护程序,Web应用程序等),但本指南将集中介绍最常见的用例:保护正在一个Servlet容器(如Tomcat或Jetty)中运行的Web应用程序。

先决条件

以下工具预计将安装在本地开发机器上,以便遵循本教程。

  • Git(1.7+)

  • Java SDK 7

  • Maven 3

选择您最喜欢的IDE,如:IntelliJ IDEA或Eclipse,甚至一个简单的文本编辑器,查看文件和进行更改。

教程格式

这是一个分步教程。 本教程及其所有步骤作为Git存储库存在。 当您克隆git存储库时,主分支是您的起点。本教程中的每一步都是一个单独的分支。可以简单地通过检查反映你当前正在审查的教程步骤的git分支。

应用程序

我们将要构建的Web应用程序是一个超级web应用程序,可以用作您自己的应用程序的起点。 在这个应用程序中将演示用户登录,注销,用户特定的欢迎消息,对Web应用程序的某些部分的访问控制,以及插入安全数据存储的集成。

我们将首先设置项目,包括构建工具和声明依赖项,以及配置servlet的web.xml文件以启动Web应用程序和Shiro环境。
完成设置后,我们将分层单独的功能,包括与安全数据存储集成,然后启用用户登录,注销和访问控制。

项目设置

这里不必手动设置目录结构和初始的基本文件集,我们已经在一个git存储库中为您做了这些工作了。

1. 下载教程项目

在GitHub上,访问教程项目,然后单击右上角的绿色clone or download按钮或者直接下载,并将下载后的文件解压到一个目录中,在本教程中放在:F:\worksp\shiro\apache-shiro-tutorial-webapp-master 目录中。

2. 项目结构

当前下载的文件目录(F:\worksp\shiro\shiro-webapp)具有以下结构:

      shiro-webapp/
      |-- src/
      |  |-- main/
      |    |-- resources/
      |      |-- logback.xml
      |    |-- webapp/
      |      |-- WEB-INF/
      |        |-- web.xml
      |      |-- home.jsp
      |      |-- include.jsp
      |      |-- index.jsp
      |-- .gitignore
      |-- .travis.yml
      |-- LICENSE
      |-- README.md
      |-- pom.xml


这里简单解释上面每个文件的含义:

  • pom.xml:Maven项目/构建文件。它配置了Jetty,因此可以通过运行mvn jetty:run来测试Web应用程序。

  • README.md:一个简单的项目自述文件。

  • LICENSE:项目的Apache 2.0许可证。

  • .travis.ymlTravis CI配置文件,可在项目上运行持续集成,用来确保它始终构建。

  • .gitignore: 一个git忽略文件,包含不应该被检入版本控制的后缀和目录。

  • src/main/resources/logback.xml: 一个简单的Logback配置文件。 对于本教程,我们选择了SLF4J作为日志记录API,Logback作为日志记录实现。也可以选择使用 Log4J 或 JUL

  • src/main/webapp/WEB-INF/web.xml:初始的web.xml文件,接下来将配置启用Shiro。

  • src/main/webapp/include.jsp:包含常见导入和声明的页面,包含在其他JSP页面中。 这允许在一个地方管理导入和声明。

  • src/main/webapp/home.jsp: 这个webapp项目的简单默认主页。 包括include.jsp

  • src/main/webapp/index.jsp: 默认站点索引页 - 只是将请求转发到home.jsp首页。

3.运行webapp

现在已经完成了项目的基本配置,可以通过在命令行上执行以下命令来运行Web应用程序:

$ mvn jetty:runBash


接下来,打开web浏览器访问:http://localhost:8080 , 应该会看到主页上有一个Hello,World!问候提示。

提示:同时按住ctrl+C关闭退出上面Web应用程序。

一、启用 Shiro

初始存储库主分支只是一个简单的通用Web应用程序,可以用作任何应用程序的模板。这里我们添加最低限度,以在Web应用程序中启用Shiro。

复制上面 shiro-webapp 项目为 shiro-webapp1

并添加了一个新的src/main/webapp/WEB-INF/shiro.ini文件, 同时修改 src/main/webapp/WEB-INF/web.xml 文件。

1. 添加 shiro.ini 文件

Shiro可以在Web应用程序中以许多不同的方式进行配置,具体取决于使用的Web和/或MVC框架。 例如,可以通过Spring,Guice,Tapestry等等来配置Shiro。

为了简化现在,我们使用Shiro的默认(非常简单)基于INI的配置来启动一个Shiro环境。
这个新的
src/main/webapp/WEB-INF/shiro.ini文件的内容(为了简洁,删除了标头注释)如下所示:

[main]

# Let's use some in-memory caching to reduce the number of runtime lookups against a remote user store.
# A real application might want to use a more robust caching solution (e.g. ehcache or a
# distributed cache).  When using such caches, be aware of your cache TTL settings: too high
# a TTL and the cache won't reflect any potential changes in Stormpath fast enough.  Too low
# and the cache could evict too often, reducing performance.
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager


这个.ini文件只包含一个带有一些最小配置的[main]块:

  • 它定义了一个新的cacheManager实例。 缓存是Shiro架构的重要组成部分 - 它减少了到各种数据存储的常规往返通信。 这个例子使用一个MemoryConstrainedCacheManager,它只对单个JVM应用程序有用。 如果应用程序部署在多个主机(例如,集群的Web服务器场)上,您需要使用集群化的CacheManager实现。

  • 它在Shiro securityManager上配置新的cacheManager实例。 Shiro SecurityManager实例始终存在,因此不需要显式定义。

2. 在web.xml中启用Shiro

虽然我们有一个shiro.ini配置,要实际加载它并启动一个新的Shiro环境,并使该环境可用于Web应用程序。还要向现有的src/main/webapp/WEB-INF/web.xml文件中添加一些内容来完成所有这些:

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>


  • <listener>声明定义了一个ServletContextListener,在Web应用程序启动时启动Shiro环境(包括Shiro SecurityManager)。 默认情况下,此侦听器自动查找用于Shiro配置的WEB-INF/shiro.ini文件。

  • <filter>声明定义主ShiroFilter。 此过滤器将过滤所有到Web应用程序的请求,以便Shiro可以在允许请求到达应用程序之前执行必要的身份和访问控制操作。

  • <filter-mapping>声明确保所有请求类型都由ShiroFilter提交。 通常,过滤器映射声明不指定<dispatcher>元素,但Shiro需要它们全部定义,因此它可以过滤可能为Web应用程序执行的所有不同的请求类型。

3. 运行webapp

完成 shiro-webapp1 项目配置后,运行Web应用程序:

$ mvn jetty:runBash


这一次,您将看到类似于以下内容的日志输出,这表明Shiro确实在webapp中运行了:

二、连接到用户存储

复制上面 shiro-webapp1 项目为 shiro-webapp2

并添加了一个新的src/main/webapp/WEB-INF/shiro.ini文件, 同时修改 src/main/webapp/WEB-INF/web.xml 文件。

在上一步中已经在webapp中集成并运行了Shiro。 但是我们没有实际告诉Shiro做任何事情。
在执行登录,注销,执行基于角色或基于权限的访问控制或任何其他安全相关之前,我们需要有用户。
我们需要配置Shiro以访问某种类型的用户存储,所以它可以查找用户执行登录尝试,或检查角色的安全决策等。任何应用程序可能需要访问的用户存储有许多类型: 也许你的用户存储在MySQL数据库,也许在MongoDB,也许你的公司的用户帐户存储在LDAP或Active Directory中的,也许你存储在一个简单的文件或一些其他专有的数据存储。

但这都不要紧,Shiro通过它称为一个领域(Realm)。Shiro文档对Realm的解释如下:

Realms act as the ‘bridge’ or ‘connector’ between Shiro and your application’s security data. When it comes time to actually interact with security-related data like user accounts to perform authentication (login) and authorization (access control), Shiro looks up many of these things from one or more Realms configured for an application.
In this sense a Realm is essentially a security-specific DAO: it encapsulates connection details for data sources and makes the associated data available to Shiro as needed. When configuring Shiro, you must specify at least one Realm to use for authentication and/or authorization. The SecurityManager may be configured with multiple Realms, but at least one is required.
Shiro provides out-of-the-box Realms to connect to a number of security data sources (aka directories) such as LDAP, relational databases (JDBC), text configuration sources like INI and properties files, and more. You can plug-in your own Realm implementations to represent custom data sources if the default Realms do not meet your needs.

因此,需要配置一个领域(Realm),以便我们可以访问用户。

3. 配置Stormpath

本教程尽可能简单,所以没有引入复杂性或范围,分散我们的学习Shiro的目的,将使用一个最简单的Realm:一个StormpathRealm

Stormpath是一个云托管的用户管理服务,完全免费用于开发目的。所以启用Stormpath后,您将以下东西就会准备好了:

  • 当学习这个教程:用于管理应用程序,目录,帐户和组的用户界面。但Shiro不提供这些,所以使用 Stormpath 是非常方便,也节省您的时间。

  • 用于用户密码的安全存储机制。应用程序从不需要担心密码安全性,密码比较或存储密码。 虽然Shiro可以做这些事情,还要你去配置它们,并知道加密概念。而Stormpath自动化密码安全,所以你(和Shiro)不需要担心它。

  • 安全工作流程,如帐户电子邮件验证和通过电子邮件重置密码。 Shiro不支持这个,因为它通常是应用程序特定。

  • 托管很方便 - 我们不必设置任何东西或维护任何东西。

对于本教程的目的,Stormpath比设置单独的RDBMS服务器和担心SQL或密码加密问题简单得多。所以我们现在就使用它吧。
当然,Stormpath只是Shiro可以通信的许多后端数据存储之一。 稍后我们将讨论更复杂的数据存储和特定于应用程序的配置。

注册Stormpath帐号

  1. 填写并提交Stormpath注册表单 - http://api.stormpath.com/register 。并发送确认电子邮件。

  2. 打开电子邮件,点击确认电子邮件中的链接,完事。

获取Stormpath API密钥
Stormpath RealmStormpath通信需要Stormpath API密钥。按以下步骤获取Stormpath API密钥:

  1. 使用您在Stormpath注册的电子邮件地址和密码登录Stormpath管理控制台

  2. 在中间右侧的结果页面上,访问页面的DEVELOPER TOOLS部分中的API Keys: Manage API Keys

  3. 在“帐户详细信息”页面的“Security Credentials”部分中,在“Api Keys”下单击“Create API Key”。这将生成您的API密钥并将其作为apiKey.properties文件下载到您的计算机。 如果在文本编辑器中打开文件,您将看到类似于以下内容的内容:

  4. apiKey.id = 144JVZINOF5EBNCMG9EXAMPLE
    apiKey.secret = lWxOiKqKPNwJmSldbiSkEbkNjgh2uRSNAb+AEXAMPLEBash
  5. 将此文件保存在安全位置,例如,在用户主目录下的.stormpath目录中。例如:

    $HOME/.stormpath/apiKey.propertiesBash
  6. 还要更改文件权限,以确保只有您可以读取此文件。 例如,在 *nix 操作系统:

    $ chmod go-rwx $HOME/.stormpath/apiKey.properties
    $ chmod u-w $HOME/.stormpath/apiKey.propertiesBash

    在Windows上,您可以类似地设置文件权限,参考:http://msdn.microsoft.com/en-us/library/bb727008.aspx 。

检索默认的Stormpath应用程序

当您注册Stormpath时,会自动为您创建一个空应用程序。 它的名称是:My Application

我们必须使用Stormpath注册我们的Web应用程序,以允许应用程序使用Stormpath进行用户管理和身份验证。 为了使用Stormpath 的 My Application 应用程序注册我们的Web应用程序,我们需要知道一些信息。我们可以使用Stormpath API检索这些信息。

首先,需要您的租户在Stormpath中的位置。使用以下方法得到:

curl -i --user $YOUR_API_KEY_ID:$YOUR_API_KEY_SECRET \'http://api.stormpath.com/v1/tenants/current'Bash


其中:
$YOUR_API_KEY_IDapiKey.properties文件中的apiKey.id
$YOUR_API_KEY_SECRETapiKey.properties文件中的apiKey.secret

执行curl后会得到这样的响应:

HTTP/1.1 302 Found
Date: Fri, 28 Aug 2015 18:34:51 GMT
Location: http://api.stormpath.com/v1/tenants/sOmELoNgRaNDoMIdHeRe
Server: Apache
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 27-Aug-2015 18:34:52 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Length: 0
Connection: keep-aliveBash


注意:Windows系统默认没有 CURL 命令,需要额外安装。请参考:http://www.baidu.com/s?wd=window+curl&

注意Location头信息。这是您的Stormpath租户的位置。 现在再次使用API检索 Stormpath 的 My Application应用程序的位置:

curl -u $API_KEY_ID:$API_KEY_SECRET \
     -H "Accept: application/json" \
     '$TENANT_HREF/applications?name=My%20Application'


其中:

$YOUR_API_KEY_IDapiKey.properties文件中的apiKey.id
$YOUR_API_KEY_SECRETapiKey.properties文件中的apiKey.secret
$TENANT_HREF是上一步骤的Location头信息的值

这个响应有很多信息。下面只是响应中的一个例子的一部分:

{
    ...
    "href": "http://api.stormpath.com/v1/applications/aLoNGrAnDoMAppIdHeRe",
    "name": "My Application",
    "description": "This application was automatically created for you in Stormpath for use with our Quickstart guides(http://docs.stormpath.com). It does apply to your subscription's number of reserved applications and can be renamed or reused for your own purposes.",
    "status": "ENABLED",
    "tenant": {
        "href": "http://api.stormpath.com/v1/tenants/sOmELoNgRaNDoMIdHeRe"
    },
    ...
}


从上面记下你的顶层href - 将使用这个hrefshiro.ini配置下。

创建应用程序测试用户帐户

现在我们有一个应用程序,接下来将要为这个应用程序创建一个sample/test用户:

curl --request POST --user $YOUR_API_KEY_ID:$YOUR_API_KEY_SECRET \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{
           "givenName": "Jean-Luc",
           "surname": "Picard",
           "username": "jlpicard",
           "email": "capt@enterprise.com",
           "password":"Changeme1"
        }' \
 "$YOUR_APPLICATION_HREF/accounts"


在上面代码中:

$YOUR_API_KEY_IDapiKey.properties文件中的apiKey.id
$YOUR_API_KEY_SECRETapiKey.properties中的apiKey.secret
$YOUR_APPLICATION_HREF是您记下的应用程序href
同样,不要忘记更改上面的网址中的
$YOUR_APPLICATION_HREF以匹配应用程序的ID

2. 配置 shiro.ini中的Realm

选择至少一个用户存储来连接到Shiro,需要配置一个Realm来代表该数据存储,然后告诉Shiro SecurityManager。

在 src/main/webapp/WEB-INF/shiro.ini 文件的[main]部分添加以下内容:

# Configure a Realm to connect to a user datastore.  In this simple tutorial, we'll just point to Stormpath since it
# takes 5 minutes to set up:
stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.cacheManager = $cacheManager

# (Optional) If you put your apiKey.properties in the non-default location, you set the location here
#stormpathClient.apiKeyFileLocation = $HOME/.stormpath/apiKey.properties

stormpathRealm = com.stormpath.shiro.realm.ApplicationRealm
stormpathRealm.client = $stormpathClient

# Find this URL in your Stormpath console for an application you create:
# Applications -> (choose application name) --> Details --> REST URL
# (Optional) If you only have one Application
#stormpathRealm.applicationRestUrl = http://api.stormpath.com/v1/applications/$STORMPATH_APPLICATION_ID

stormpathRealm.groupRoleResolver.modeNames = name
securityManager.realm = $stormpathRealm


注意可选行:

如果您已经使用Stormpath一段时间,并且有多个Stormpath应用程序,则必须设置stormpathRealm.applicationRestUrl属性。

3. 运行webapp

按照步骤1步骤2中的指定进行更改后,继续并运行Web应用程序:

mvn jetty:run


这一次,您将看到类似于以下的日志输出,表明Shiro和新的 Realm 在您的webapp中正确配置:

16:08:25.466 [main] INFO  o.a.shiro.web.env.EnvironmentLoader - Starting Shiro environment initialization.
16:08:26.201 [main] INFO  o.a.s.c.IniSecurityManagerFactory - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
16:08:26.201 [main] INFO  o.a.shiro.web.env.EnvironmentLoader - Shiro environment initialized in 731 ms.


三、启用登录和注销

现在我们有用户,可以在UI中轻松添加,删除和禁用它们。 现在可以在我们的应用程序中启用诸如登录/注销和访问控制等功能。

复制上面 shiro-webapp2 项目为 shiro-webapp3

并添加以下2个附加文件:

  • 添加了一个新的src/main/webapp/login.jsp文件和一个简单的登录表单以使用它来登录。

  • 更新shiro.ini文件,以支持特定于Web(URL)的功能。

1. 启用Shiro表单登录和注销支持

将 src/main/webapp/WEB-INF/shiro.ini 文件包含以下2个附加项:

[main]

shiro.loginUrl = /login.jsp

# Stuff we've configured here previously is omitted for brevity

[urls]
/login.jsp = authc
/logout = logout


shiro.* 行

[main]部分的顶部,添加有一个新行

shiro.loginUrl = /login.jsp


这是一个特殊的配置指令,告诉Shiro“对于任何具有loginUrl属性的Shiro默认过滤器,我希望将属性值设置为/login.jsp“。

这允许Shiro的默认authc过滤器(默认情况下,FormAuthenticationFilter)了解登录页面。 这是FormAuthenticationFilter正常工作所必需的。

[urls]部分

[urls]部分是一个新的特定于web的INI部分。

本部分允许您使用非常简洁的名称/值对语法来告诉shiro如何过滤任何给定URL路径的请求。 [urls]中的所有路径都是相对于Web应用程序的HttpServletRequest.getContextPath()) 值。

这些名称/值对提供了一种非常强大的方法来过滤请求,允许各种安全规则。 更深的URL和过滤器链的覆盖范围超出了本文档的范围,但如果你有兴趣,请阅读: http://shiro.apache.org/web.html#Web-%7B%7B%5Curls%5C%7D%7D 。

现在,我们将介绍说明以下添加的两行:

/login.jsp = authc
/logout = logout


  • 第一行表示“每当Shiro看到对/login.jsp的 URL 请求时,请求期间启用Shiro authc过滤器”。

  • 第二行表示“每当Shiro看到对/logout的 URL 请求,请求期间启用Shiro logout 过滤器。

这两个过滤器有点特别:实际上不需要任何东西“在它们的后面”。他们实际上只是完全处理请求。没有任何东西可以处理这些URL - 因为没有编写任何控制器! Shiro将根据需要处理请求。

2. 添加登录页面

由于步骤3启用登录和注销支持,现在我们需要确保有一个/login.jsp页面来显示登录表单。

在这个新的src/main/webapp/login.jsp页面中。 这是一个简单的引导主题的HTML登录页面,它有四个重要的事情:

  1. 表单的操作值是空字符串。当表单没有操作值时,浏览器会将表单请求提交到同一个网址。 Shiro可以自动处理任何登录提交。shiro.ini中的/login.jsp = authc行是告诉authc过滤器处理提交的内容。

  2. 有一个用户名(username)表单字段。 Shiro authc过滤器将在登录提交期间自动查找用户名(username)请求参数,并将其用作登录期间的值(许多Realms允许这是电子邮件或用户名)。

  3. 有一个密码(password)表单字段。 Shiro authc过滤器将在登录提交期间自动查找密码请求参数。

  4. 有一个rememberMe复选框,其“选中”状态可以是“true”值(truet1enabledyyesopen)。

login.jsp中的表单只使用默认的:用户名,密码和rememberMe表单字段名。 如果想要更改这些名称,可以配置这些名称 - 有关更改配置信息,请参阅FormAuthenticationFilter JavaDoc

3. 运行webapp

按照步骤1步骤2中的指定进行更改后,继续并运行Web应用程序:

mvn jetty:run


4. 尝试登录

使用Web浏览器,导航访问: localhost:8080/login.jsp , 将看到新的登录表单。

输入您在步骤2结束时创建的帐户的用户名和密码,然后点击“登录”。 如果登录成功,您将被定向到主页! 如果登录失败,您将再次显示登录页面。


相关问答

更多
  • 一、前言 Apache Shiro与Spring Security一样是Java的一个安全框架。那为什么与Spring整合却用Shiro?不要问为什么,任性!开个玩笑:D 其实我个人是认为Spring Security太过于笨重,要写太多的过滤器。我是个怕麻烦的人,Shiro的配置简单这就是我选择的理由,何况Spring官方自己都推荐使用Shiro。而Shiro权限控制与CAS单点登录的组合更是堪称Java安全中的***~( ̄_, ̄ )……但本文只介绍它们三者的整合配置(说白了就是给自己留个学习笔记啦),若 ...
  • 不知道你转为web项目意义何在,可能是为了在线对爬取的配置,首先:nutch2.2.1提供了一个API,实现其相应的接口,就可以实现相应的功能了,第二点:nutch本身爬取就需要占用大规模的资源,支持hadoop的,hadoop本身就是离线的,所以设置成web意义不大。 所以建议去实现nutch的API接口进行爬取,然后用web项目查询数据就好了
  • 我整合过,没用ini文件。
  • 配置Shiro的filter,因为在web系统中,Shiro也是通过filter进行拦截。【Shiro会提供很多filter】 下面的filter拦截后,会将操作权给我等等在下面贴出的applicationContext-shiro.xml(Spring中配置的filter,过滤链)!
  • 一、前言 Apache Shiro与Spring Security一样是Java的一个安全框架。那为什么与Spring整合却用Shiro?不要问为什么,任性!开个玩笑:D 其实我个人是认为Spring Security太过于笨重,要写太多的过滤器。我是个怕麻烦的人,Shiro的配置简单这就是我选择的理由,何况Spring官方自己都推荐使用Shiro。而Shiro权限控制与CAS单点登录的组合更是堪称Java安全中的***~( ̄_, ̄ )……但本文只介绍它们三者的整合配置(说白了就是给自己留个学习笔记啦),若 ...
  • 基于缺乏兴趣和支持,我选择编写自己的身份验证处理程序。 Based on the lack of interest and support I chose to write my own authentication handler.