用户
许多应用程序的核心功能中,都有用户帐户的概念,它让用户以安全的方式访问自己的信息。我们提供一个专门的用户类Parse.User,可以自动处理用户帐户管理所需的大部分功能。
通过这个类,您可以在应用中添加用户帐户。
Parse.User是Parse.Object的子类,并具有其所有的特性,如灵活的Schema模式,自动持久化和键值接口。Parse.Object所有的方法也存在于Parse.User。区别在于Parse.User具有额外的针对用户帐户的特殊功能。
1.Parse.User的属性
Parse.User有几个不同于Parse.Object的字段:
- username:用户的用户名(必填)。
- password:用户密码(注册需要)。
- email:用户的电子邮件地址(可选)。
当我们运行用户的各种用例时,我们将详细介绍这些。
2.注册
您的应用程序第一件事可能是要求用户注册。以下代码展示了典型的注册过程:
var user = new Parse.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("email", "email@example.com");
// other fields can be set just like with Parse.Object
user.set("phone", "415-392-0202");
user.signUp(null, {
success: function(user) {
// Hooray! Let them use the app now.
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}
});
此调用将在您的Parse App中异步创建一个新用户。在此之前,它还会检查以确保用户名和电子邮件都是唯一的。此外,它使用bcrypt安全地在云中对密码进行哈希。我们从不以明文存储密码,也不会以明文形式传送密码给客户端。
请注意,我们使用的signUp方法,而不是save方法。应始终使用signUp方法来创建Parse.User。而用户的后续更新可以通过调用save来完成。
如果注册不成功,您可读取到返回的错误对象。最可能的情况是用户名或电子邮件已被其他用户占用。您应该清楚地将其传达给您的用户,并要求其尝试不同的用户名。
您可以自由使用电子邮件地址作为用户名。只需要求用户输入他们的电子邮件,但把它填写到用户名属性中——
Parse.User将正常工作。之后我们还将介绍如何处理重置密码部分。
3.登录
当然,在用户注册后,您将需要他们登录到自己的帐户。为此,您可以使用logIn类方法。
Parse.User.logIn("myname", "mypass", {
success: function(user) {
// Do stuff after successful login.
},
error: function(user, error) {
// The login failed. Check error to see why.
}
});
4.验证电子邮件
在应用程序设置中启用电子邮件验证,使得应用程序可利用确认的电子邮件地址为用户提供更多服务。电子邮件验证在Parse.User对象添加了一个emailVerified键。当Parse.User的email被设置或修改时,emailVerified被设定为false。然后Parse会向用户发送一个链接可将emailVerified设置为true。
有三个emailVerified状态要考虑:
- true - 用户已通过点击Parse发送给他们的链接确认了他/她的电子邮件地址。首次创建用户帐户时,该状态绝不会是true。
- false- 当Parse.User对象最近更新时,用户尚未确认他/她的电子邮件地址。如果emailVerified是false,考虑调用Parse.User的fetch方法。
- missing - 当电子邮件验证被关闭时创建Parse.User,或Parse.User中电子邮件字段没有值。
5.当前用户
如果用户每次打开您的应用程序时都要登录,将会很麻烦。您可以通过缓存当前Parse.User对象来避免这种情况。
无论何时使用任何注册或登录方法,用户都将被缓存在localStorage中。您可以将此缓存视为会话,并自动假定用户已登录:
var currentUser = Parse.User.current();
if (currentUser) {
// do stuff with the user
} else {
// show the signup or login page
}
您可以通过登出方法清除当前用户:
Parse.User.logOut().then(() => {
var currentUser = Parse.User.current(); // this will now be null
});
6.设置当前用户
如果您已经创建了自己的身份验证规程,或者以其他方式登录到服务器端,则可以使用become方法将会话令牌(sessionToken)传递给客户端。此方法将确保设置当前用户之前会话令牌是有效的。
Parse.User.become("session-token-here").then(function (user) {
// The current user is now set to user.
}, function (error) {
// The token could not be validated.
});
7.用户对象的安全
默认情况下Parse.User类是安全的。存储在Parse.User中的数据只能由该用户修改。默认情况下,任何客户端仍然可以读取数据。因此,一些Parse.User对象被认证并可以被修改,而其他对象是只读的。
具体而言,你不能调用任何save或delete方法,除非是通过已认证的方法获取到Parse.User,例如logIn或signUp。这确保只有用户可以更改自己的数据。
以下代码说明了此安全策略:
var user = Parse.User.logIn("my_username", "my_password", {
success: function(user) {
user.set("username", "my_new_username"); // attempt to change username
user.save(null, {
success: function(user) {
// This succeeds, since the user was authenticated on the device
// Get the user from a non-authenticated method
var query = new Parse.Query(Parse.User);
query.get(user.objectId, {
success: function(userAgain) {
userAgain.set("username", "another_username");
userAgain.save(null, {
error: function(userAgain, error) {
// This will error, since the Parse.User is not authenticated
}
});
}
});
}
});
}
});
从Parse.User.current()获得的Parse.User将始终是已被认证的。
如果您需要检查Parse.User是否已通过身份验证,则可以调用authenticated方法。那些由被认证的方法获取的Parse.User对象不需要authenticated方法检查。
8.其他对象的安全
适用于Parse.User安全模型同样可应用于其他对象。对于任何对象,您可以指定哪些用户可以读取对象,哪些用户可以修改对象。为了支持这种类型的安全性,每个对象都有一个由Parse.ACL类实现的访问控制列表(access control list)。
使用Parse.ACL最简单的方法是指定对象只能由单个用户读取或写入。这可通过用一个Parse.User来初始化Parse.ACL来完成:new Parse.ACL(user)生成一个Parse.ACL,限制仅该用户有访问权限。像对象的任何其他属性一样,保存对象时就会更新对象的ACL。因此,创建只能由当前用户访问的私人笔记可以这样:
var Note = Parse.Object.extend("Note");
var privateNote = new Note();
privateNote.set("content", "This note is private!");
privateNote.setACL(new Parse.ACL(Parse.User.current()));
privateNote.save();
此笔记只能由当前用户访问,不论该用户登录到何种设备都可以。此功能对于要在多个设备上访问用户数据的应用程序(例如个人待办事项清单)很有用。
也可以在每个用户的基础上授予权限。您可以使用setReadAccess和setWriteAccess方法为Parse.ACL单独添加权限。例如,假设您有一个消息要发送到好几个用户,其中每个用户都有权读取和删除该消息:
var Message = Parse.Object.extend("Message");
var groupMessage = new Message();
var groupACL = new Parse.ACL();
// userList is an array with the users we are sending this message to.
for (var i = 0; i < userList.length; i++) {
groupACL.setReadAccess(userList[i], true);
groupACL.setWriteAccess(userList[i], true);
}
groupMessage.setACL(groupACL);
groupMessage.save();
您也可以使用setPublicReadAccess和setPublicWriteAccess方法一次性为所有用户授予权限。这适用于在留言板上发表评论之类的场景。例如,要创建一个只能由其作者编辑的帖子,但可以由任何人阅读:
var publicPost = new Post();
var postACL = new Parse.ACL(Parse.User.current());
postACL.setPublicReadAccess(true);
publicPost.setACL(postACL);
publicPost.save();
被禁止的操作(如删除不具有写访问权限的对象)会导致Parse.Error.OBJECT_NOT_FOUND错误代码。为了安全起见,返回这样的错误代码可以防止客户端区分出哪些对象id存在但是被安全保护的,哪些对象id根本不存在。
9.重置密码
事实上,一旦系统有密码,用户可能会忘记它们。在这种情况下,我们提供了一种让他们安全地重置密码的方法。
要启动密码重设流程,请用户提供他们的电子邮件地址,然后调用:
Parse.User.requestPasswordReset("email@example.com", {
success: function() {
// Password reset request was sent successfully
},
error: function(error) {
// Show the error message somewhere
alert("Error: " + error.code + " " + error.message);
}
});
它会尝试将给定的电子邮件与用户的电子邮件或用户名字段进行匹配,并向他们发送密码重置电子邮件。通过这种方式,您可以选择让用户使用他们的电子邮件作为用户名,或者您可以分别收集它们并将其存储在电子邮件字段中。
密码重置流程如下:
- 用户通过输入他们的电子邮件请求重置密码。
- Parse发送电子邮件到他们的邮箱,并提供一个特殊的密码重置链接。
- 用户单击重置链接,并被导向一个特殊的Parse页面,要求他们键入新的密码。
- 用户键入新密码。他们的密码现在已经重置为他们指定的值。
请注意,此流程中的消息传递将通过您在Parse上创建此应用程序时指定的名称来引用您的应用程序。
10.查询
要查询用户,您可以为Parse.Users创建一个新的Parse.Query:
var query = new Parse.Query(Parse.User);
query.equalTo("gender", "female"); // find all the women
query.find({
success: function(women) {
// Do stuff
}
});
11.关联(Associations)
关联使得Parse.User工作于一个闭环。例如,假设您正在编写一个博客应用程序。要存储用户的新帖子并检索他们的所有帖子:
var user = Parse.User.current();
// Make a new post
var Post = Parse.Object.extend("Post");
var post = new Post();
post.set("title", "My New Post");
post.set("body", "This is some great content.");
post.set("user", user);
post.save(null, {
success: function(post) {
// Find all posts by the current user
var query = new Parse.Query(Post);
query.equalTo("user", user);
query.find({
success: function(usersPosts) {
// userPosts contains all of the posts by the current user.
}
});
}
});
12.Facebook用户
Parse提供了一种在您的应用程序中集成Facebook的简单方法。Parse.FacebookUtils类集成了Parse.User和Facebook的JavaScript SDK,使您的用户可以很容易的链接到他们的Facebook身份。
通过我们的Facebook集成方法,您可以让Parse.User与已验证的Facebook用户相关联。只需几行代码,您就可以在应用程序中提供“登录Facebook”选项,并且可以将其数据保存到Parse。
1.设置FACEBOOK
要在Parse中使用Facebook,您需要:
- 设置一个Facebook应用程序,如果你还没有的话。在“选择应用程序与Facebook集成的方式”下选择“使用网站登录Facebook”选项,然后输入您网站的URL。
- 在您的Parse应用程序的设置页面上添加您的应用程序的Facebook应用程序ID。
- 按照以下说明将Facebook JavaScript SDK加载到您的应用程序中。
- 替换调用FB.init()的语句为调用Parse.FacebookUtils.init()。例如,如果您异步加载Facebook JavaScript SDK,您的fbAsyncInit函数将如下所示:
<script>
// Initialize Parse
Parse.initialize("$PARSE_APPLICATION_ID", "$PARSE_JAVASCRIPT_KEY");
window.fbAsyncInit = function() {
Parse.FacebookUtils.init({ // this line replaces FB.init({
appId : '{facebook-app-id}', // Facebook App ID
status : true, // check Facebook Login status
cookie : true, // enable cookies to allow Parse to access the session
xfbml : true, // initialize Facebook social plugins on the page
version : 'v2.3' // point to the latest Facebook Graph API version
});
// Run code after the Facebook SDK is loaded.
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
一旦Facebook JavaScript SDK完成加载,赋给fbAsyncInit的函数就会运行。Facebook JavaScript SDK加载完成后,且在调用Parse.FacebookUtils.init()之后,你想要运行的任何代码都应放在此函数内。
如果您遇到任何与Facebook相关的问题,Facebook的官方入门指南是一个很好的资源。
如果遇到从Parse服务器返回的问题,请尝试从应用的设置页面中删除您的Facebook应用程序的App Secret。
通过Parse Users使用Facebook有两种主要方式:(1)以Facebook用户身份登录,创建一个Parse.User;或(2)将Facebook连接到现有的Parse.User。
2.登陆&注册
Parse.FacebookUtils提供了一种允许您通过Facebook登录或注册Parse.User的方法。这是使用logIn()方法实现的:
Parse.FacebookUtils.logIn(null, {
success: function(user) {
if (!user.existed()) {
alert("User signed up and logged in through Facebook!");
} else {
alert("User logged in through Facebook!");
}
},
error: function(user, error) {
alert("User cancelled the Facebook login or did not fully authorize.");
}
});
运行此代码时,会发生以下情况:
- 该用户被显示在Facebook登录对话框中。
- 用户通过Facebook进行身份验证,您的应用程序会收到回调。
- 我们的SDK收到Facebook数据并将其保存到Parse.User。如果是基于Facebook ID的新用户,则创建该用户。
- 连同用户一起,您的success回调被调用。
此外,您还可以提供以逗号分隔的字符串,该字符串指定您的应用程序从Facebook用户那里要哪些权限。例如:
Parse.FacebookUtils.logIn("user_likes,email", {
success: function(user) {
// Handle successful login
},
error: function(user, error) {
// Handle errors and cancellation
}
});
Parse.User集成不需要任何立即可用的权限(即null或任何权限都不指定,是完全可以接受的)。更多关于权限的信息请阅读Facebook开发者指南。
3.链接
验证后,您可以从Facebook用户保存您需要的任何数据。要完成此操作,您需要使用Facebook SDK进行图查询(graph query )。
如果您想将现有Parse.User的帐户与Facebook帐户相关联,则可以像这样链接:
if (!Parse.FacebookUtils.isLinked(user)) {
Parse.FacebookUtils.link(user, null, {
success: function(user) {
alert("Woohoo, user logged in with Facebook!");
},
error: function(user, error) {
alert("User cancelled the Facebook login or did not fully authorize.");
}
});
}
链接时发生的事情与登录非常相似,不同之处在于成功登录后,当前的Parse.User信息将随Facebook信息更新,而未来通过Facebook登录将会将用户登录到现有帐户中。
如果您想要将Facebook与用户取消关联,请执行以下操作:
Parse.FacebookUtils.unlink(user, {
success: function(user) {
alert("The user is no longer associated with their Facebook account.");
}
});
4.FACEBOOK SDK和PARSE
Facebook Javascript SDK提供了一个主FB对象,这是与Facebook的API进行许多交互的起点。您可以在这里阅读到更多关于他们SDK的信息。
使用Parse SDK进行Facebook登录时,需要在调用Parse.FacebookUtils.init()前Facebook SDK已完成加载。
我们的代码库为您管理FB对象。该FB单例默认与当前用户同步,因此您调用的任何方法将作用于与当前Parse.User用户相关联的Facebook用户。显式调用FB.login()或FB.logOut()会导致Parse.User和FB对象不同步,因此不推荐这样做。
13.链接用户
Parse允许您将用户与Twitter和Facebook等服务相链接,使您的用户可以使用其现有身份注册或登录到您的应用程序。这是通过_linkWith()方法、由您想链接到的用户服务的authData字段提供认证数据来实现。一旦您的用户与服务相关联,该服务的authData将与用户一起存储,并可通过登录进行检索。
authData是一个JSON对象,每个关联服务的键包含以下数据。在每种情况下,要自己负责完成身份验证流程(例如,在客户端使用hellojs的OAuth 1.0a),以获取链接服务所需的信息。
1.FACEBOOK AUTHDATA
{
"facebook": {
"id": "user's Facebook id number as a string",
"access_token": "an authorized Facebook access token for the user",
"expiration_date": "token expiration date of the format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
}
}
进一步了解关于Facebook登录的信息。
2.TWITTER AUTHDATA
{
"twitter": {
"id": "user's Twitter id number as a string",
"screen_name": "user's Twitter screen name",
"consumer_key": "your application's consumer key",
"consumer_secret": "your application's consumer secret",
"auth_token": "an authorized Twitter token for the user with your application",
"auth_token_secret": "the secret associated with the auth_token"
}
}
进一步了解Twitter登录的信息。
3.匿名用户 AUTHDATA
{
"anonymous": {
"id": "random UUID with lowercase hexadecimal digits"
}
}
4.注册并登录
使用链接服务注册用户并使用该服务登录,使用了相同的_linkWith()方法,都需要指定用户的authData。例如,要使用用户的Twitter帐户注册或登录:
let myAuthData = {
"id": "12345678",
"screen_name": "ParseIt",
"consumer_key": "SaMpLeId3X7eLjjLgWEw",
"consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
"auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
}
let user = new Parse.User();
user._linkWith('twitter', myAuthData).then(function(user){
// user
});
Parse会验证提供的authData是否有效,并检查用户是否已经与此数据相关联。如果是这样,它返回状态码“200 OK”和详细信息(包括用户的sessionToken):
Status: 200 OK
Location: https://api.parse.com/1/users/uMz0YZeAqc
响应体类似这样:
{
"username": "Parse",
"createdAt": "2012-02-28T23:49:36.353Z",
"updatedAt": "2012-02-28T23:49:36.353Z",
"objectId": "uMz0YZeAqc",
"sessionToken": "r:samplei3l83eerhnln0ecxgy5",
"authData": {
"twitter": {
"id": "12345678",
"screen_name": "ParseIt",
"consumer_key": "SaMpLeId3X7eLjjLgWEw",
"consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
"auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
}
}
}
如果用户从未与此帐户相关联,则会接收到状态代码201 Created,表示已创建新用户:
Status: 201 Created
Location: https://api.parse.com/1/users/uMz0YZeAqc
响应体将包含objectId、createdAt、sessionToken,和自动生成的唯一username。例如:
{
"username": "iwz8sna7sug28v4eyu7t89fij",
"createdAt": "2012-02-28T23:49:36.353Z",
"objectId": "uMz0YZeAqc",
"sessionToken": "r:samplei3l83eerhnln0ecxgy5"
}
5.链接
将现有用户与Facebook或Twitter之类的服务相关联,使用了相同的_linkWith()方法去关联用户的authData。例如,将用户与Facebook帐户关联会使用以下请求:
let myAuthData = {
id: "123456789",
"access_token": "SaMpLeAAibS7Q55FSzcERWIEmzn6rosftAr7pmDME10008bWgyZAmv7mziwfacNOhWkgxDaBf8a2a2FCc9Hbk9wAsqLYZBLR995wxBvSGNoTrEaL",
"expiration_date": "2012-02-28T23:49:36.353Z"
}
let user = new Parse.User();
user.id = "uMz0YZeAqc";
user._linkWith("facebook", myAuthData).then(function(user){
// user is linked now
});
将用户连接到服务后,您可以使用匹配的authData进行身份验证。
6.取消链接
将现有用户与服务断开连接也使用_linkWith()方法,它通过设置服务的authData为null去清除用户的authData。例如,取消用户与Facebook帐户的链接将使用如下请求:
let user = new Parse.User();
user.id = "uMz0YZeAqc";
user._linkWith("facebook", {}).then(function(user){
// user is unlinked now
});