使用 Play Framework 和 Scala 管理用户身份验证(1)
- UID
- 1066743
|
使用 Play Framework 和 Scala 管理用户身份验证(1)
在现代 Web 应用程序中实现身份验证可能需要大量的工作。您需要使用户能够通过多种机制(凭据;使用 OAuth1、OAuth2 或 OpenID 的社交服务提供商)执行身份验证。用户注册和密码重置通常需要基于电子邮件的流。请求和查看也必须知道登录用户的身份(如果有)。
本教程介绍一个使用 构建的入门级身份验证应用程序。Play 是 新一代反应式 Web 框架(比如 Node.js 和 Vert.x)中的一员。Play 还带来了开发友好的特性,比如原生的 XML 和 JSON 处理,开发模式下的浏览器内错误报告,内置的测试帮助器,以及 Selenium 集成。您可在 Java™ 或 Scala 中编写 Play 应用程序,但首选 Scala。函数语言最适合反应式编程风格。尽管 Java 最终在第 8 版中接受了函数编程概念,但它落后于 Scala 丰富的函数特性储备。
我的入门级应用程序通过实现以下功能展示了 Scala 和 Play 的实际运用:
Play 的可伸缩性通过使用异步 I/O,Play 采取了一种编程模型,其中应用程序代码对在 I/O 完成时触发的事件做出反应。在此期间,运行应用程序代码的线程不会拦截,而能够处理其他请求。此设计支持高效地使用处理器核心:Play 可使用少量线程处理大量的流量。而且 Play 不会存储任何服务器端会话状态,它通过消除会话亲缘性而帮助实现了水平可伸缩性:集群中的任何服务器都可受理一个请求。
- 基于电子邮件的用户注册
- 凭据(电子邮件和密码)和通过 OAuth1 进行的 Twitter 身份验证
- 基于电子邮件的密码重置
- 凭据和 Twitter 帐户链接
- 用户感知的视图、HTTP 请求和 Ajax 调用的示例
该应用程序使用 执行身份验证工作,使用 实现用户持久性。所有请求处理和与 MongoDB 的交互都是完全异步的。您可使用此应用程序作为您自己的项目的起点,省得自己从头实现身份验证。
我假设您基本熟悉 Scala 语言。(如果您拥有 Java 背景且需要了解 Scala,我建议您阅读 developerWorks 系列。)我还假设您至少拥有最基本的 Play 经验;拥有控制器、路由和视图的基本知识就足够了。有关 Play 的介绍,请参阅 的 “入门” 小节。(本教程的代码使用 Play Framework 2.4.2 版,所以请阅读该版本的文档。)一定要查阅本系列的 ,我将在其中展示如何将 Play 应用程序部署在 IBM Bluemix™ 上。
设置Play 的应用采用 Play 的公司包括 、 和 。撰写本文时,该项目在 GitHub 上已有 2,411 个分支,Stack Overflow 上有 10,308 个带 playframework 标记的问题。
要构建和运行这个入门级应用程序,您需要在系统上安装 Play 2.4.2 或更高版本和 MongoDB。
安装 MongoDB 和 Play 按照 MongoDB 网站的 小节中针对您平台的说明,安装 MongoDB。在大多数 Linux 发行版上,您可使用相应的包管理器安装 MongoDB。对于 Mac,您可使用 Homebrew;对于 Windows,可使用 MSI 安装程序。
Play Framework(自 2.4.0 版开始)需要 Java 8,所以请确保您安装了 Java SE 8 SDK。要安装 Play,请 并解压极小的激活程序 — 一个 1MB 的 ZIP 文件,包含将在第一次运行时下载 Play 的代码和依赖项(约 450MB)的启动脚本。为方便起见,您可能希望将激活程序的文件夹添加到您的系统路径中。
下载和运行应用程序 示例应用程序项目托管在 上。您可克隆该项目的 Git 存储库(必须首先登录或注册)来获取源代码。也可参阅 来获取应用程序的 ZIP 文件。拥有代码后,执行以下步骤来运行该应用程序:
- 在 网站上注册一个应用程序。输入 http://dwdemo.com:9000/auth/social/twitter 作为回调 URL。
- 将 127.0.0.1 dwdemo.com 添加到您的 hosts 文件中,以便该应用程序可被在 Twitter 上注册的同一个域找到。
- 通过将来自 Twitter 应用程序页上的相应值复制到 conf/silhouette.conf 文件中的第 28 和 29 行,设置用户密钥和用户机密属性。
- 运行 mongod --dbpath folder 来启动 MongoDB 服务器,其中 folder 是 MongoDB 将存储数据库文件的目录。
- 要启动该应用程序,转到您克隆了代码的根文件夹并对它执行 activator run。
应用程序启动(首次执行这一步将需要一些时间)后,转到 http://dwdemo.com:9000 来打开它。您会看到一个欢迎屏幕,用户可在其中注册来在应用程序中创建一个帐户。
应用程序配置设置好您的环境后,就可以钻研应用程序配置了。
主要配置文件 主要配置文件是 conf/application.conf,这是 Play 寻找配置属性的默认位置。清单 1 显示了相关部分。
清单 1. conf/application.conf1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| play.modules.enabled += "play.modules.reactivemongo.ReactiveMongoModule"
play.modules.enabled += "module.Module"
mongodb.uri = "mongodb://localhost:27017/demodb"
mail.from="dwplaydemo <mailrobot@dwplaydemo.net>"
mail.reply="No reply <noreply@dwplaydemo.net>"
play.mailer {
mock = true
host = localhost
}
play.http.filters = "utils.Filters"
play.http.errorHandler = "utils.ErrorHandler"
include "silhouette.conf"
|
application.conf 文件声明两个配置依赖注入绑定的类。ReactiveMongoModule 使反应式 Mongo 绑定可注入到应用程序类中。module.Module 类指定应用程序的注入绑定,主要针对 Silhouette 类。mongodb.uri 属性定义如何连接到 MongoDB,play.mailer 设置一个模拟邮件服务,用于在开发模式下测试注册和密码重置流。一个模拟的邮件收发器将电子邮件记录到控制台;在生产中,该应用程序必须使用一个 SMTP 服务器。
utils.Filters 类定义应用程序的过滤器管道。目前,这个类使用 Play 的跨站请求伪造 (CSRF) 过滤器来保护 POST 请求。utils.ErrorHandler 类拥有设置应用程序全局请求错误处理策略的作用;它为内部服务器和页面未找到条件定义错误页面重定向。更重要的是,对于对受保护资源的未授权或未验证的访问尝试,该类还定义了向登录页面的重定向。包含的 silhouette.conf 文件声明了特定于 Silhouette 的设置。我将在 “ ” 一节中介绍这些设置。
应用程序路由 conf/routes 文件定义了特定于应用程序的页面的路由和身份验证流。 清单 2 显示了特定于应用程序的路由。
清单 2. 特定于应用程序的路由1
2
3
4
5
6
7
8
9
10
| # Application
GET / controllers.Application.index
GET /profile controllers.Application.profile
# Rest api
GET /rest/profile controllers.RestApi.profile
# Public assets
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
GET /webjars/*file controllers.WebJarAssets.at(file)
|
该应用程序包含两个页面。索引页面是用户感知的,适用于登录的用户或匿名访问。概况页面是受保护的,需要授权才能访问(否则,它会重定向到索引页面)。/rest/profile URL 映射到一个安全的 REST API 端点,该端点以 JSON 格式返回登录用户的概况信息。最后两个 URL 是公共资产的标准路由,比如样式表、图像和 JavaScript 代码。 清单 3 显示了身份验证路由和流。
清单 3. 身份验证路由1
2
3
4
5
6
7
8
9
10
11
12
13
| GET /auth/signup controllers.Auth.startSignUp
POST /auth/signup controllers.Auth.handleStartSignUp
GET /auth/signup/:token controllers.Auth.signUp(token:String)
GET /auth/reset controllers.Auth.startResetPassword
POST /auth/reset controllers.Auth.handleStartResetPassword
GET /auth/reset/:token controllers.Auth.resetPassword(token:String)
POST /auth/reset/:token controllers.Auth.handleResetPassword(token:String)
GET /auth/signin controllers.Auth.signIn
POST /auth/authenticate controllers.Auth.authenticate
GET /auth/social/:providerId controllers.Auth.socialAuthenticate(providerId:String)
GET /auth/signout controllers.Auth.signOut
|
注册流从对注册页面的 GET 请求开始。从该页面,用户通过 POST 将他们的注册信息(电子邮件地址、密码、姓名)提交给 /auth/signup。应用程序通过发送一封电子邮件来处理该提交,邮件中包含一个 /auth/signup/:token URL,用户必须访问该 URL 才能完成注册操作。密码重置流类似:用户通过 GET 获取密码重置页面,他们在其中通过 POST 将一个电子邮件地址提交给 /auth/reset。此提交会生成一封包含一个 /auth/reset/:token URL 的电子邮件。这个 URL 将用户带到一个页面,他们可在其中输入一个新密码并通过 POST 将其提交到 /auth/reset/:token 来完成该过程。
/auth/signin 路由提供了访问登录页面的路径。auth/authenticate 路由是执行凭据验证的 URL 端点,/auth/social/:providerId 是执行社交验证的端点。目前,唯一受支持的社交服务提供商是 Twitter,通过 OAuth1 实现。/auth/signout 路由公开用于从应用程序注销的端点。 |
|
|
|
|
|