1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
---
title: 快速安装
slug: Mozilla/Persona/Quick_Setup
tags:
- Mozilla
- Persona
translation_of: Archive/Mozilla/Persona/Quick_Setup
---
<p>要把 Persona 登录系统添加到你的站点只需要 5 步:</p>
<ol>
<li>在你的页面中包含 Persona 的 JavaScript 库。</li>
<li>添加“登入”和“登出”按钮。</li>
<li>监视登入和登出行为。</li>
<li>验证用户证书。</li>
<li>回顾最佳实现。</li>
</ol>
<p>你应该能在一个下午就建立好并运行,但重要的是:如果你要在你的站点上使用 Persona,请花一点时间订阅 <a href="https://mail.mozilla.org/listinfo/persona-notices">Persona 通知</a> 邮件列表。它流量非常低,只用于通知那些对你站点有负面影响的变更或安全问题。</p>
<h2 id="步骤1:包含_Persona_库">步骤1:包含 Persona 库</h2>
<p>Persona 被设计为跨浏览器且可在<a href="https://developer.mozilla.org/docs/persona/Browser_compatibility">全部主要桌面和移动浏览器</a>中工作。</p>
<p>在未来我们期望浏览器提供 Persona 的原生支持,但我们同时提供了一个 JavaScript 库完整地实现了用户界面和客户端部分的协议。通过包含这个库,你的用户会可以用 Persona 登入,无论他们的浏览器是否有原生支持。</p>
<p>一 旦页面中的这个库加载完毕,你需要的 Persona 函数({{ domxref("navigator.id.watch()", "watch()") }}、{{ domxref("navigator.id.request()", "request()") }} 和 {{ domxref("navigator.id.logout()", "logout()") }})会在全局对象 <code>navigator.id</code> 中可用。</p>
<p>要包含 Persona JavaScript 库,你可以把这个 <code>script</code> 标签放进你页面的首部:</p>
<pre class="brush: html;"><script src="https://login.persona.org/include.js"></script>
</pre>
<p>你<strong>必须</strong>在每个使用 {{ domxref("navigator.id") }} 中函数的页面里包含这个标签。因为 Persona 始终在开发中,你不应该自行托管 <code>include.js</code> 文件。</p>
<h2 id="步骤2:添加登入登出按钮">步骤2:添加登入/登出按钮</h2>
<p>因 为 Persona 被设计为一个 DOM API,你必须在用户点击你站点上的登入或登出按钮时调用函数。要打开 Persona 对话框并提示用户登入,你应该调用 {{ domxref("navigator.id.request()") }} 。而登出要调用 {{ domxref("navigator.id.logout()") }} 。</p>
<p>例如:</p>
<pre class="brush: js;">var signinLink = document.getElementById('signin');
if (signinLink) {
signinLink.onclick = function() { navigator.id.request(); };
};
var signoutLink = document.getElementById('signout');
if (signoutLink) {
signoutLink.onclick = function() { navigator.id.logout(); };
};
</pre>
<p>那些按钮的是什么样子的?查看我们的<a href="https://developer.mozilla.org/docs/persona/branding">品牌资源</a>页面中的预制图片和基于 CSS 的按钮!</p>
<h2 id="步骤3:监视登入登出行为">步骤3:监视登入/登出行为</h2>
<p>要把 Persona 封装成函数,你需要告诉它当用户登入/登出时做什么。调用 {{ domxref("navigator.id.watch()") }} 函数就可以实现,它支持三个参数:</p>
<ol>
<li>
<p>你站点当前用户的 <code>loggedInEmail</code> ,如果没有则为 <code>null</code> 。你应该在渲染页面的时候动态生成它。</p>
</li>
<li>
<p>当触发 <code>onlogin</code> 行为的时候调用的函数。这个函数会被传递一个必须认证的“身份断言”参数。</p>
</li>
<li>
<p>当触发 <code>onlogout</code> 行为的时候调用的函数。这个函数不会被传递任何参数。</p>
</li>
</ol>
<div class="note style-wrap">
<p><strong>注意:</strong>你必须总是在调用 {{ domxref("navigator.id.watch()") }} 时同时包含 <code>onlogin</code> 和 <code>onlogout</code> 。</p>
</div>
<p>例如,如果你现在认为鲍勃已经登入到你的站点,你会这样做:</p>
<pre class="brush: js;">var currentUser = 'bob@example.com';
navigator.id.watch({
loggedInUser: currentUser,
onlogin: function(assertion) {
// 一个用户已经登入!这是你需要做的:
// 1. 把断言发送到后端验证并创建一个会话。
// 2. 更新你的 UI。
$.ajax({ /* <-- 本例使用了 jQuery,但你也可以用你想用的 */
type: 'POST',
url: '/auth/login', // 这是你网站上的一个 URL
data: {assertion: assertion},
success: function(res, status, xhr) { window.location.reload(); },
error: function(res, status, xhr) { alert("登入失败" + res); }
});
},
onlogout: function() {
// 一个用户已经登出!这是你需要做的:
// 销毁用户的会话并重定向用户或做后端的调用。
// 同样,让 loggedInUser 在下个页面加载时变为 null。
// (这是一个字面的 JavaScript null。不是 false、 0 或 undefined。null。)
$.ajax({
type: 'POST',
url: '/auth/logout', // 这是你网站上的一个 URL
success: function(res, status, xhr) { window.location.reload(); },
error: function(res, status, xhr) { alert("登出失败" + res); }
});
}
});
</pre>
<p>在本例中,<code>onlogin</code> 和 <code>onlogout</code> 都通过向你站点的后端发送异步 <code>POST</code> 请求来实现。后端随后通常用设定或删除会话 cookie 中的信息来登入或登出用户。之后,如果一切都核对无误,页面重加载来考虑账户的新登录状态。</p>
<p>你当然可以用 AJAX 来不用重加载或重定向来实现,但这超出了本教程的范畴。</p>
<p>你<strong>必须</strong>在每个有登入/登出按钮的页面上调用这个函数。要为用户支持 Persona 加强功能,诸如自动登录和全局登出,你<strong>应该</strong>在网站上的每个页面都调用这个函数。</p>
<h2 id="步骤4:验证用户证书">步骤4:验证用户证书</h2>
<p>Persona 用“身份断言”来代替密码,那是一种类似一次性、单站点的、用户邮件地址捆绑的密码。当用户想要登入时,你的 <code>onlogin</code> 回调会传入一个该用户的断言来调用。在你登入他们前,你必须验证断言的有效性。</p>
<p>在你的服务器上而不是用户浏览器上运行的 JavaScript 中验证断言是<em>极度</em>重要的,因为那很容易伪造。上面的例子用 jQuery 的 <code>$.ajax()</code> 辅助函数来把断言通过 <code>POST</code> 到 <code>/auth/login</code> 来呈递给后端。</p>
<p>一旦你的服务器获得了断言,你如何验证它?最简单的方法是用 Mozilla 提供的辅助服务。简单地把断言以两个参数 <code>POST</code> 给 <code>https://verifier.login.persona.org/verify</code>:</p>
<ol>
<li><code>assertion</code>: 用户提供的身份断言。</li>
<li><code>audience</code>: 你网站的主机名和端口。你必须在后端硬编码这个值;不要从用户提供的任何数据中派生这个值。</li>
</ol>
<p>例如,如果你是 <code>example.com</code>,你可以用下面的命令行来测试断言:</p>
<pre class="brush: bash;">$ curl -d "assertion=<ASSERTION>&audience=https://example.com:443" "https://verifier.login.persona.org/verify"
</pre>
<p>如果它是有效的,你会得到像这样的一个 JSON 响应:</p>
<pre class="brush: js;">{
"status": "okay",
"email": "bob@eyedee.me",
"audience": "https://example.com:443",
"expires": 1308859352261,
"issuer": "eyedee.me"
}
</pre>
<p>你可以阅读<a href="https://developer.mozilla.org/en-US/docs/BrowserID/Remote_Verification_API">验证服务 API</a>来获知更多关于验证服务的内容。一个 <code>/api/login</code> 实现的使用了 <a href="http://python.org/">Python</a>、<a href="http://flask.pocoo.org/">Flask</a> web 框架和 <a href="http://python-requests.org">Requests</a> HTTP 库的例子看起来是这样:</p>
<pre class="brush: python;">@app.route('/auth/login', methods=['POST'])
def login():
# 请求必须包含我们要验证的断言
if 'assertion' not in request.form:
abort(400)
# 把断言发送给 Mozilla 的验证服务
data = {'assertion': request.form['assertion'], 'audience': 'https://example.com:443'}
resp = requests.post('https://verifier.login.persona.org/verify', data=data, verify=True)
# 验证器响应了吗?
if resp.ok:
# 处理响应
verification_data = json.loads(resp.content)
# 检查断言是否有效
if verification_data['status'] == 'okay':
# 设置一个安全会话 cookie 来登入用户
session.update({'email': verification_data['email']})
return resp.content
# 哎哟,有什么东西不对,放弃
abort(500)
</pre>
<p>会话管理可能很像你现有的登录系统。首先的大区别是在验证用户身份采用了检查断言而不是检查密码。另一个不同是确保用户的邮件地址有效来用于 {{ domxref("navigator.id.watch()") }} 的 <code>loggedInEmail</code> 参数</p>
<p>登出很简单:你只需要移除用户的会话 cookie。</p>
<h2 id="步骤5:回顾最佳实践">步骤5:回顾最佳实践</h2>
<p>一旦所有的东西都工作正常并且你已经成功登入和登出你的站点,你应该花一会时间来回顾安全可靠地使用 Persona 的<a href="https://developer.mozilla.org/docs/BrowserID/Security_Considerations">最佳实践</a>。</p>
<p>如果你在做一个要作为生产环境的站点,你会想要编写集成的测试来模拟用 Persona 登入或登出用户。要改善 Selenium 中的这个行为,请考虑使用 <a href="https://github.com/mozilla/bidpom" title="https://github.com/mozilla/bidpom">bidpom</a> 库。<a href="https://mockmyid.com/" title="https://mockmyid.com/">mockmyid.com</a> 和 <a href="http://personatestuser.org" title="http://personatestuser.org">personatestuser.org</a> 这两个网站也可能会有用。</p>
<p>最后,不要忘记登记加入 <a href="https://mail.mozilla.org/listinfo/persona-notices">Persona 通知</a> 邮件列表,这样会通知你任何安全问题或 Persona API 的向后兼容变更。这个列表的流量非常低:它只用于通知会对你的站点造成负面影响的变更。</p>
|