Skip to content

2.07 用户和角色

Arvin(张心彧) edited this page Mar 6, 2019 · 2 revisions

用户

用户是一个应用程序的核心。对于个人开发者来说,自己的应用程序积累到越多的用户,就会给自己带来越强的创作动力。因此Bmob提供了一个专门的用户类——BmobUser来自动处理用户账户管理所需的功能。

有了这个类,你就可以在你的应用程序中添加用户账户功能。

BmobUser是BmobTable的一个子类,它继承了BmobTable所有的方法,具有BmobTable相同的功能。不同的是,BmobUser增加了一些特定的关于用户账户管理相关的功能。

属性

BmobUser除了从BmobTable继承的属性外,还有几个特定的属性:

  • username: 用户的用户名(必需)。
  • password: 用户的密码(必需)。
  • email: 用户的电子邮件地址(可选)。

创建用户对象

创建用户对象如下:

BmobUser user = new BmobUser();

如果你需要扩展用户资料信息,如给用户表添加生命值life和攻击指数attack,那么需要创建一个新的用户类,继承自BmobUser。示例代码如下:

public class GameUser : BmobUser
{
	public BmobInt life { get; set; }
	public BmobInt attack { get; set; }

	public override void write(BmobOutput output, bool all)
	{
		base.write(output, all);

		output.Put("life", this.life);
		output.Put("attack", this.attack);
	}

	public override void readFields(BmobInput input)
	{
		base.readFields(input);

		this.life = input.getInt("life");
		this.attack = input.getInt("attack");
	}
}

注册用户

你的应用程序可能会要求用户注册。下面的代码是一个典型的注册过程:

BmobUser user = new BmobUser();
user.username = "bmob";
user.password = "123456";
//邮箱用于找回密码
user.email = "[email protected]";
//如使用了GameUser表的话,以下注册语句需要更改为:bmobUnity.Signup<MyBmobUser>(user,(resp, exception) =>
bmobUnity.Signup(user,(resp, exception) =>
{
	if (exception != null)
	{
		print("注册失败, 失败原因为: " + exception.Message);
		return;
	}
	print("注册成功");
});

在注册过程中,服务器会对注册用户信息进行检查,以确保注册的用户名和电子邮件地址是独一无二的。此外,对于用户的密码,你可以在应用程序中进行相应的加密处理后提交。

如果注册不成功,你可以查看返回的错误对象。最有可能的情况是,用户名或电子邮件已经被另一个用户注册。这种情况你可以提示用户,要求他们尝试使用不同的用户名进行注册。

你也可以要求用户使用Email做为用户名注册,这样做的好处是,你在提交信息的时候可以将输入的“用户名“默认设置为用户的Email地址,以后在用户忘记密码的情况下可以使用Bmob提供重置密码功能。

这里需要注意一点的是,有些时候你可能需要在用户注册时发送一封验证邮件,以确认用户邮箱的真实性。这时,你只需要登录自己的应用管理后台,在应用设置->邮件设置(下图)中把“邮箱验证”功能打开,Bmob云后端就会在注册时自动发动一封验证给用户。

设置邮箱验证功能

登录用户

当用户注册成功后,您需要让他们以后能够用注册的用户名登录到他们的账户使用应用。要做到这一点,你可以使用BmobUser类的login方法。

bmobUnity.Login<GameUser>("bmob", "123456", (resp, exception) => 
{
	if (exception != null)
	{
		print("登录失败, 失败原因为: " + exception.Message);
		return;
	}

	print("登录成功, @" + resp.username + "(" + resp.life + ")$[" + resp.sessionToken + "]");
	print("登录成功, 当前用户对象Session: " + BmobUser.CurrentUser.sessionToken);
});

获取当前用户

登录之后,你可以通过如下示例代码获取当前登录用户的信息:

BmobUser buser = BmobUser.CurrentUser;
// 或者
GameUser user = BmobUser.CurrentUser as GameUser;

更新用户

很多情况下你可能需要修改用户信息,比如你的应用具备修改个人资料的功能,示例代码如下:

GameUser user = new GameUser();
user.attack = 1000;
//需要知道用户记录的objectId和sessionToken信息
bmobUnity.UpdateUser("objectid", user, "sessionToken", (resp, exception) =>
{
	if (exception!= null)
	{
		print("保存失败, 失败原因为: " + exception.Message);
		return;
	}

	print("保存成功, @" + resp.updatedAt);
});

在更新用户信息时,如果用户邮箱有变更并且在管理后台打开了邮箱验证选项的话,Bmob云后端同样会自动发一封邮件验证信息给用户。

查询用户

查询用户和查询普通对象一样,只需指定BmobUser类即可,如下查询用户名为bmob的用户:

BmobQuery query = new BmobQuery();
query.WhereEqualTo("username", "bmob");
bmobUnity.Find<GameUser>(BmobUser.TABLE, query, (resp, exception) =>
{
	if (exception != null)
	{
		print("查询失败, 失败原因为: " + exception.Message);
		return;
	}

	List<GameUser> list = resp.results;
	foreach (var user in list)
	{
		print("获取的对象为: " + user.ToString());
	}
});

浏览器中查看用户表

User表是一个特殊的表,专门存储BmobUser对象。在浏览器端,你会看到一个User表旁边有一个小人的图标。

密码重置

一旦你引入了一个密码系统,那么肯定会有用户忘记密码的情况。对于这种情况,我们提供了一种方法,让用户安全地重置起密码。

重置密码的流程很简单,开发者只需要求用户输入注册的电子邮件地址即可,示例代码如下:

bmobUnity.Reset("[email protected]", (resp, exception) =>
{
	if (exception != null)
	{
		print("重置密码请求失败, 失败原因为: " + exception.Message);
		return;
	}

	print("重置密码请求发送成功!");
});

密码重置流程如下:

  • 用户输入他们的电子邮件,请求重置自己的密码。
  • Bmob向他们的邮箱发送一封包含特殊的密码重置连接的电子邮件。
  • 用户根据向导点击重置密码连接,打开一个特殊的Bmob页面,根据提示他们可以输入一个新的密码。
  • 用户的密码已被重置为新输入的密码。

邮箱验证

设置邮件验证是一个可选的应用设置, 这样可以对已经确认过邮件的用户提供一部分保留的体验,邮件验证功能会在用户(User)对象中加入emailVerified字段, 当一个用户的邮件被新添加或者修改过的话,emailVerified会被默认设为false,如果应用设置中开启了邮箱认证功能,Bmob会对用户填写的邮箱发送一个链接, 这个链接可以把emailVerified设置为 true.

emailVerified 字段有 3 种状态可以考虑:

  • true : 用户可以点击邮件中的链接通过Bmob来验证地址,一个用户永远不会在新创建这个值的时候显示emailVerified为true。
  • false : 用户(User)对象最后一次被刷新的时候, 用户并没有确认过他的邮箱地址, 如果你看到emailVerified为false的话,你可以考虑刷新用户(User)对象。
  • missing : 用户(User)对象已经被创建,但应用设置并没有开启邮件验证功能; 或者用户(User)对象没有email邮箱。

请求验证Email

发送给用户的邮箱验证邮件会在一周内失效,可以通过调用 EmailVerify 来强制重新发送:

bmobUnity.EmailVerify("[email protected]", (resp, exception) => 
{
	if (exception != null)
	{
		print("邮箱验证请求失败, 失败原因为: " + exception.Message);
		return;
	}

	print("邮箱验证请求发送成功!");
});

ACL和角色

数据安全是软件系统中最重要的组成部分,为了更好的保护应用数据的安全,Bmob在软件架构层面提供了应用层次、表层次、ACL(Access Control List:访问控制列表)、角色管理(Role)四种不同粒度的权限控制的方式,确保用户数据的安全(详细请查看Bmob数据与安全页面,了解Bmob如何保护数据安全)。

其中,最灵活的方法是通过ACL和角色,它的思路是每一条数据有一个用户和角色的列表,以及这些用户和角色拥有什么样的许可权限。

大多数应用程序需要对不同的数据进行灵活的访问和控制,这就可以使用Bmob提供的ACL模式来实现。例如:

  • 对于私有数据,读写权限可以只局限于数据的所有者。
  • 对于一个论坛,会员和版主有写的权限,一般的游客只有读的权限。
  • 对于日志数据只有开发者才能够访问,ACL可以拒绝所有的访问权限。
  • 属于一个被授权的用户或者开发者所创建的数据,可以有公共的读的权限,但是写入权限仅限于管理者角色。
  • 一个用户发送给另外一个用户的消息,可以只给这些用户赋予读写的权限。
  • 用Bmob SDK,你可以对这些数据设置一个默认的ACL,这样,即使黑客反编译了你的应用,获取到Application Key,也仍然无法操作和破坏你的用户数据,确保了用户数据的安全可靠。而作为开发者,当你需要对这些数据进行管理时,可以通过超级权限Key(Master Key)进行。

默认访问权限

在没有显示指定的情况下,每一个BmobTable中的ACL(列)属性的默认值是所有人可读可写的。在客户端想要修改这个权限设置,只需要简单调用BmobACL的ReadAccess方法和WriteAccess方法,如设置所有用户的读权限为true,写权限为false的示例代码如下:

BmobACL acl = new BmobACL();
acl.ReadAccess("*");

这里说明一点的是: *号表示所有用户。ACL列为空表示所有用户可读可写;在不为空的情况下,读或写空缺表示没有对应权限。

指定用户的访问权限

如果你想对发表的微博设定一个权限:发表微博的作者有修改和删除的权限,其他用户只有读的权限,那么,可用如下的示例代码:

//创建数据对象
Weibo weibo = new Weibo();
weibo.message = "论电影的七个元素";
//创建一个ACL对象
BmobACL acl = new BmobACL();    
//设置所有人可读
acl.ReadAccess("*");
//参数是用户的objectId,这里设置为当前用户可写    
acl.WriteAccess(BmobUser.CurrentUser().objectId);   
//设置这条数据的ACL信息
weibo.ACL = acl;    
bmobUnity.Create(TABLENAME, weibo, (resp, exception) =>
{
	if(exception != null){
		print("保存失败, 失败原因为: " + exception.Message);
		return;
	}

	print("保存成功, @" + resp.createdAt);
});

如果要设定只有微博的作者有读写权限,其他人都没有读写权限,那么,可用如下的示例代码:

//创建数据对象
Weibo weibo = new Weibo();
weibo.message = "论电影的七个元素";
//创建一个ACL对象
BmobACL acl = new BmobACL();    
//参数是用户的objectId,这里设置为当前用户可读
acl.ReadAccess(BmobUser.CurrentUser().objectId);
//参数是用户的objectId,这里设置为当前用户可写    
acl.WriteAccess(BmobUser.CurrentUser().objectId);   
//设置这条数据的ACL信息
weibo.ACL = acl;    
bmobUnity.Create(TABLENAME, weibo, (resp, exception) =>
{
	if(exception != null){
		print("保存失败, 失败原因为: " + exception.Message);
		return;
	}

	print("保存成功, @" + resp.createdAt);
});

角色管理

上面的指定用户访问权限虽然很方便,但是对于有些应用可能会有一定的局限性。比如一家公司的工资系统,员工和公司的出纳们只拥有工资的读权限,而公司的人事和老板才拥有全部的读写权限。要实现这种功能,你也可以通过设置每个用户的ACL权限来实现,如下:

//创建公司某用户的工资对象
WageInfo wageinfo = new WageInfo();
wageinfo.Wage = 100000;   

//这里创建四个用户对象,分别为老板、人事小张、出纳小谢和自己
BmobUser boss;
BmobUser hr_zhang;
BmobUser cashier_xie;
BmobUser me;

//创建ACL对象
BmobACL acl = new BmobACL();

//设置四个用户读的权限
acl.ReadAccess(boos.objectId);    
acl.ReadAccess(hr_zhang.objectId);
acl.ReadAccess(cashier_xie.objectId);
acl.ReadAccess(me.objectId);

//设置老板和人事小张对这个工资的写权限
acl.WriteAccess(boss.objectId);
acl.WriteAccess(hr_zhang.objectId);

//设置工资对象的ACL
wageinfo.ACL =acl;
bmobUnity.Create(TABLENAME, wageinfo, (resp, exception) =>
{
	if(exception != null){
		print("保存失败, 失败原因为: " + exception.Message);
		return;
	}

	print("保存成功, @" + resp.createdAt);
});

但是,一个公司的人事、出纳和员工不仅仅只有一个人,同时还会有离职、调换岗位以及新员工加入等问题存在。如果用上面的代码对公司的每个人进行一一设置的话是不现实的,既麻烦也很难维护。针对这个问题,我们可以利用BmobRole来解决。我们只需要对用户进行分类,每个分类赋予不同的权限。如下代码实现:

//这里创建四个用户对象指针,分别为老板、人事小张、出纳小谢和自己
// just for test
BmobPointer<BmobUser> boss = new BmobUser() { objectId = "1" };
BmobPointer<BmobUser> hr_zhang = new BmobUser() { objectId = "2" };
BmobPointer<BmobUser> hr_luo = new BmobUser() { objectId = "3" };
BmobPointer<BmobUser> cashier_xie = new BmobUser() { objectId = "4" };
BmobPointer<BmobUser> me = new BmobUser() { objectId = "5" };

{
	//创建HR和Cashier两个用户角色(这里为了举例BmobRole的使用,将这段代码写在这里,正常情况下放在员工管理界面会更合适)
	BmobRole hr = new BmobRole();
	hr.name = "HR";
	var users = new BmobRelation<BmobUser>();
	users.Add(hr_zhang);
	users.Add(hr_luo);

	//将hr_zhang和hr_luo归属到hr角色中
	hr.AddUsers(users);

	//保存到云端角色表中(web端可以查看Role表)
	var future = Bmob.CreateTaskAsync(hr);
	FinishedCallback(future.Result, null);
}

{
	BmobRole cashier = new BmobRole();
	cashier.name = "Cashier";
	var users = new BmobRelation<BmobUser>();
	users.Add(cashier_xie);

	//将cashier_xie归属到cashier角色中
	cashier.AddUsers(users);

	//保存到云端角色表中(web端可以查看Role表)
	var future = Bmob.CreateTaskAsync(cashier);
	FinishedCallback(future.Result, null);
}

根据Role设置ACL:

//创建公司某用户的工资对象
WageInfo wageinfo = new WageInfo();
wageinfo.Wage =100000;

//创建ACL对象
BmobACL acl = new BmobACL();
acl.setReadAccess(boos, true); // 假设老板只有一个, 设置读权限
acl.setReadAccess(me, true); // 给自己设置读权限
// 给hr角色设置读权限
acl.RoleReadAccess(hr.name);
// 给cashier角色设置读权限
acl.RoleReadAccess(cashier.name);

// 设置老板拥有写权限
acl.RoleWriteAccess(boss.name);
// 设置hr角色拥有写权限
acl.RoleWriteAccess(hr.name);

//设置工资对象的ACL
wageinfo.ACL = acl;
//添加数据
bmobUnity.Create(TABLENAME, wageinfo, null);

需要说明一点的是,Web端的Role表也具有ACL的列,你可以将角色管理的权限赋予某些用户。