用户登录
介绍
本篇,我们将介绍用户登录功能。学习完后,你将可以完成登录、顶号、禁止重复登录等功能。
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 是一个扩展性极强的框架,这样的需求也是支持扩展的。扩展步骤如下
- 给用户数据关联一个 long 类型的 id,比如 Snowflake。
- 将 objectId 存放到元信息-附加信息中
- 配合自定义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;
}
}