跳到主要内容

用户登录

介绍

本篇,我们将介绍用户登录功能。学习完后,你将可以完成登录、顶号、禁止重复登录等功能。

Example Source Code

see https://github.com/iohao/ionet-examples

path : ionet-cookbook-code

  • HallAction

登录

我们定义一个数据协议 UserMessage,用于处理登录业务返回的用户信息。

  • code 7,flowContext.bindingUserId 方法是登录的关键代码,目的是在对外服的 channel 中设置用户的真实 userId。 之后用户的每次请求,可以通过 FlowContext 来获取该用户的相关信息。
@ActionController(HallCmd.cmd)
public class HallAction {
...
@ActionMethod(HallCmd.loginVerify)
private UserMessage loginVerify(String jwt, FlowContext flowContext) {
long userId = Math.abs(jwt.hashCode());

boolean success = flowContext.bindingUserId(userId);
ErrorCode.loginFailed.assertTrue(success);

return UserKit.ofUserMessage(userId);
}
}

@ToString
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class UserMessage {
long id;
String nickname;
}
注意

一定要调用框架提供的这个方法才算是用户验证成功,否则后续在 FlowContext 上下文中拿不到 userId。

禁止重复登录

禁止重复登录指的是相同的号已经在线上了,不能重复登录该账号了。

  • code 3,检测用户是否在线,当用户在线时就触发断言。
  • code 4,断言+异常机制,如果用户在线就返回错误码给请求端。
private UserMessage loginVerify(String jwt) {
long userId = Math.abs(jwt.hashCode());
boolean existUser = CommunicationKit.existUser(userId);
ErrorCode.userOnline.assertTrueThrows(existUser);
...
}

顶号

顶号指的是相同的号已经在线上了,把线上的号顶下线。

  • code 3,强制指定用户下线。
private UserMessage loginVerify(String jwt) {
long userId = Math.abs(jwt.hashCode());
CommunicationKit.forcedOffline(userId);
...
}

UserId

登录后,可以通过 FlowContext 来获取 userId。

public long hello(FlowContext flowContext) {
return flowContext.getUserId();
}

userId 可以支持 String 类型的 Id 吗?

业务需求: 如果 userId 不是 long 类型的怎么办?我使用的是 MongoDB objectId 是 String 类型的。

ionet 是一个扩展性极强的框架,这样的需求也是支持扩展的。扩展步骤如下

  1. 给用户数据关联一个 long 类型的 id,比如 Snowflake
  2. 将 objectId 存放到元信息-附加信息
  3. 配合自定义FlowContext
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class MyAttachment {
long userId;
/** MongoDB objectId */
String objectId;
}

@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MyFlowContext extends DefaultFlowContext {
MyAttachment attachment;

@Override
public MyAttachment getAttachment() {
if (Objects.isNull(this.attachment)) {
this.attachment = this.getAttachment(MyAttachment.class);
}

return this.attachment;
}

public String getUserIdString() {
var attachment = this.getAttachment(MyAttachment.class);
return attachment.objectId;
}
}