todo: 使用融云imserve做登录(android)
使用融云做登录注册思路
- 注册界面需要name, email, password
- 考虑到融云注册用户的post格式
POST http://api.rong-api.com/user/getToken.json?userId=1690544550qqcom&name=Ironman
- 这里的userId可以使用用户的email,但是要截断
@
和.
符号,即1690544550@qq.com -> 1690544550qqcom
, 融云不让我传完整的邮箱地址,这里可能要考虑到奇怪的邮箱地址,如fuckerfucker@fucker.edu.cn
,我不确定截断后的是fuckerfuckerfuckereducn
能不能还原成邮箱地址 - 注册的name传入post 参数的name
- 融云注册返回格式
{"code": 200,"userId": "1690544550qqcom","token": "测试"
}
- 那android注册界面需要检查返回的response的
code==200
和token!=null
, 如果ok,注册用户成功 - 登录界面需要email和password, 这里
可能还要考虑到自己搭建服务后端来存取用户基本信息(email, password)
- 但是查到融云一条api是关于查询用户信息的
POST http://api.rong-api.com/user/info.json?userId=1690544550qqcom
接口返回
{"code": 200,"userName": "Ironman","userPortrait": "http://abc.com/myportrait.jpg","createTime": "2025-03-05 11:46:49"
}
- 现在考虑怎么
校验密码
那一块,校验密码能不能本地校验
,就是注册的时候拿到email和password存到手机本地数据库,到登录时,需要用userId请求融云用户信息,检查code==200, 密码就比对本地数据库的email, password一对,好像相对繁琐了 - 登录成功后跳转界面
- 完啦,注册的页面还要考虑到验证邮箱地址正确,就是发邮箱验证码,这不知道怎么入手
todo实现以上思路
1. 使用go语言简单搭建一个邮箱验证码服务,邮箱服务来自qq邮箱
- 后端地址: https://gitee.com/EEPPEE_admin/dont-want-to-write-code-anymore/tree/master/send_code_to_mail
- 配置自己的qqmail 授权码还有自己的发送邮箱地址
- 提供接口
### 发送验证码,这里的email是从adnroid客户端注册用户获取
POST http://localhost:8080/send-code?email=1876056356@qq.com
### 验证验证码, 738702 是验证码,有发送验证码获取,随机的,这里的email是从adnroid客户端注册用户获取
POST http://localhost:8080/verify-code?email=1876056356@qq.com&code=6271
2. 搭建data层调式邮箱验证码
- 先启动后端go run main.go
- 创建data/network/EmailVerifyCodeApiService.kt
// Base url:https://7f498cbc.r7.cpolar.top
interface EmailVerifyCodeApiService {@POST("send-code")fun sendVerificationCode(@Query("email") email: String): Call<VerifyCodeResponse>@POST("verify-code")fun verifyEmailCode(@Query("email") email: String,@Query("code") code: String): Call<VerifyCodeResponse>}// 邮箱验证码的返回
data class VerifyCodeResponse(val message: String
)object EmailVerifyCodeApiClient {// todo: 这个base url随时变动,根据你的cpolar地址来private const val BASE_URL = "https://7f498cbc.r7.cpolar.top"private var apiService: EmailVerifyCodeApiService? = nullval emailVerifyCodeApiService: EmailVerifyCodeApiService?get() {if (apiService == null) {val client: OkHttpClient = OkHttpClient.Builder().build()val retrofit = Retrofit.Builder().baseUrl(BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create()).build()apiService = retrofit.create(EmailVerifyCodeApiService::class.java)}return apiService}
}
- 测试点击发送邮件事件(这个简单界面代码就不给出了,就一个按钮,一个EditText,使用viewbinding)
binding.sendBtn.setOnClickListener {val email = binding.emailEt.text.toString().trim()// todo: 处理发送邮箱验证码val apiService = EmailVerifyCodeApiClient.emailVerifyCodeApiServiceval call = apiService?.sendVerificationCode(email)call!!.enqueue(object : retrofit2.Callback<VerifyCodeResponse> {override fun onResponse(call: Call<VerifyCodeResponse>,response: Response<VerifyCodeResponse>) {Log.d("注册", response.body().toString())Log.d("注册", "发送邮箱验证码成功")}override fun onFailure(call: Call<VerifyCodeResponse>, t: Throwable) {Log.d("注册", "发送验证码失败")}})}
- 测试邮箱验证码发送通过
3. 调试融云api
- 创建data/network/RongCloudApiService.kt
// todo: 构建融云api服务, 接口里面的方法可以是suspend和普通函数
/*
普通函数 vs. suspend 函数
普通函数:
使用回调(Callback)或 Call 对象来处理异步请求。
适用于传统的异步编程模型。
代码相对复杂,需要处理回调和线程切换。
suspend 函数:
使用 Kotlin 协程来处理异步请求。
代码更简洁,更接近同步编程风格。
需要结合 CoroutineScope 或其他协程工具来调用。
示例代码*/
interface RongCloudApiService {@FormUrlEncoded@POST("user/getToken.json")fun getToken(// 这是x-form形式@Field("userId") userId: String, // todo: required@Field("name") name: String = "",@Field("portraitUri") portraitUri: String = ""): Call<GetTokenResponse>// @POST("user/info.json")
// fun getRongCloudUserInfo(
// @Query("userId") userId: String
// ): Response<RongCloudUserInfo>@FormUrlEncoded@POST("user/info.json")fun getUserInfo(@Field("userId") userId: String,): Call<UserInfoResponse>}// user/getToken.json接口的返回
data class GetTokenResponse(val code: Int,val userId: String,val token: String?
)// user/info.json接口的返回
data class UserInfoResponse(val code: Int,val userName: String,val userPortrait: String?,val createTime: String
)object RongCloudApiClient {// 要求不能明文传输,改成httpsprivate const val BASE_URL = "https://api.rong-api.com/"private const val APP_KEY = "你自己的"private const val NONCE = "1442907399"private const val TIMESTAMP = "1741092643"private const val SIGNATURE = "你自己的"private var apiService: RongCloudApiService? = null// todo: 获取实例方法val rongIMApiService: RongCloudApiService?get() {if (apiService == null) {val client: OkHttpClient = OkHttpClient.Builder().addInterceptor(Interceptor { chain ->val originalRequest: Request = chain.request()val newRequest: Request = originalRequest.newBuilder().header("App-Key", APP_KEY).header("Nonce", NONCE).header("Timestamp", TIMESTAMP).header("Signature", SIGNATURE).header("Content-Type", "application/x-www-form-urlencoded").build()chain.proceed(newRequest)}).build()val retrofit = Retrofit.Builder().baseUrl(BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create()).build()apiService = retrofit.create(RongCloudApiService::class.java)}return apiService}
}
- 调试代码,点击一个注册按钮,观察Logcat
binding.registerBtn.setOnClickListener {val email = binding.emailEt.text.toString().trim()Log.d("注册", email)val name = binding.nameEt.text.toString().trim()Log.d("注册", name)val password = binding.passwordEt.text.toString().trim()Log.d("注册", password)val mailVerifyCode = binding.mailVerifycodeEt.text.toString().trim()Log.d("注册", mailVerifyCode)if (name.isEmpty() || email.isEmpty() || password.isEmpty() || mailVerifyCode.isEmpty()) {Toast.makeText(this, "请填充完整信息", Toast.LENGTH_SHORT).show()return@setOnClickListener}// email 处理成 userIdval processedEmailAsUserId = EmailUtil.convertEmailToRongCloudId(email)Log.d("注册", processedEmailAsUserId)// todo 取到接口实例val apiService = RongCloudApiClient.rongIMApiService// todo 调用api serviceval call = apiService?.getToken(processedEmailAsUserId,name)// todo call 进入队列call!!.enqueue(object : retrofit2.Callback<GetTokenResponse> {override fun onResponse(call: Call<GetTokenResponse>,response: retrofit2.Response<GetTokenResponse>) {Log.d("注册", response.body().toString())//RongCloudTokenResponse(code=200, userId=13266263124qqcom, token=Seq1kNg6Uft4UOBPzi2gGqh30okEsnM0kPAf6ohCvgf1vll6L9v54A==@ptfq.cn.rongnav.com;ptfq.cn.rongcfg.com)}override fun onFailure(call: Call<GetTokenResponse>, t: Throwable) {Log.d("注册", "获取token失败")}})// todo new call 进入队列val newcall = apiService?.getUserInfo(processedEmailAsUserId)newcall!!.enqueue(object : retrofit2.Callback<UserInfoResponse> {override fun onResponse(call: Call<UserInfoResponse>,response: Response<UserInfoResponse>) {Log.d("注册", response.body().toString())// UserInfoResponse(code=200, userName=好, userPortrait=http://abc.com/myportrait.jpg, createTime=2025-03-05 16:51:19)}override fun onFailure(call: Call<UserInfoResponse>, t: Throwable) {Log.d("注册", "获取用户信息失败")}})}
todo还要考虑谷歌和facebook登录情况
相关文章:

todo: 使用融云imserve做登录(android)
使用融云做登录注册思路 注册界面需要name, email, password考虑到融云注册用户的post格式 POST http://api.rong-api.com/user/getToken.json?userId1690544550qqcom&nameIronman这里的userId可以使用用户的email,但是要截断和 . 符号,即1690544…...

Mac OS升级后变慢了,如何恢复老系统?
我的一台Mac Air闲置很久了,原因是某次系统升级后用着会卡,有差不多10年没用了。今天想试着恢复一下出厂系统,目前看这条路可以走通。记录如下: 1、去哪里下载旧版系统? https://support.apple.com/zh-cn/102662 2、…...

cursor使用经验分享(java后端服务开发向)
前言 cursor是一款基于vscode,并集成AI能力的代码编辑器,其功能包括但不限于代码生成及补全、AI对话(能够直接将代码环境作为上下文)、即时应用建议等等,是一款面向未来的代码编辑器。 对于vscode,最先想…...

初次使用 IDE 搭配 Lombok 注解的配置
前言 在 Java 开发的漫漫征程中,我们总会遇到各种提升效率的工具。Lombok 便是其中一款能让代码编写变得更加简洁高效的神奇库。它通过注解的方式,巧妙地在编译阶段为我们生成那些繁琐的样板代码,比如 getter、setter、构造函数等。然而&…...

vue 安装依赖npm install过程中报错npm ERR! cb() never called!
解决办法: 步骤 1:清理 npm 缓存 npm cache clean --force rm -rf node_modules package-lock.json 步骤 2:一个第三方 npm 工具包,功能是 自动重试失败的 npm install 操作,适用于网络不稳定或依赖源不可靠的场景 …...

android接入rocketmq
一 前言 RocketMQ 作为一个功能强大的消息队列系统,不仅支持基本的消息发布与订阅,还提供了顺序消息、延时消息、事务消息等高级功能,适应了复杂的分布式系统需求。其高可用性架构、多副本机制、完善的运维管理工具,以及安全控制…...

libilibi项目优化(1)使用Redis实现缓存
第一版 获取视频信息使用旁路缓存 当视频信息存在缓存中时(命中),直接从缓存中获取。不存在缓存中时,先从数据库中查出对应的信息,写入缓存后再放回数据。 //获取视频详细信息RequestMapping("/getVideoInfo&q…...

The Rust Programming Language 学习 (二)
通用编程概念 变量和可变性 默认情况下变量是不可变的(immutable),不过你也可以选择让变量是可变的(mutable). 变量的遮蔽 你可以声明和前面变量具有相同名称的新变量,说这个是第一个变量被第二个变量遮蔽(shadow&…...

http链接转成https的链接的几种方法
以下是一个将HTTP链接转换为HTTPS的JavaScript函数,处理了多种常见输入情况: function convertToHttps(url) {if (typeof url ! string) return url;// 移除首尾空格并处理空字符串const trimmedUrl url.trim();if (!trimmedUrl) return https://;// 替…...

STM32——串口通信 UART
一、基础配置 Universal Asynchronous Receiver Transmitter 异步,串行,全双工 TTL电平 :高电平1 低电平0 帧格式: 起始位1bit 数据位8bit 校验位1bit 终止位1bit NVIC Settings一栏使能接受中断。 之前有设置LCD,…...

mybatis日期格式与字符串不匹配bug
异常特征:java.lang.IllegalArgumentException: invalid comparison: java.time.LocalDateTime and java.lang.String ### Error updating database. Cause: java.lang.IllegalArgumentException: invalid comparison: java.time.LocalDateTime and java.lang.Str…...

文献分享: ConstBERT固定数目向量编码文档
😂图放这了,大道至简的 idea \text{idea} idea不愧是 ECIR \text{ECIR} ECIR 👉原论文 1. ConstBERT \textbf{1. ConstBERT} 1. ConstBERT的原理 1️⃣模型的改进点:相较于 ColBERT \text{ColBERT} ColBERT为每个 Token \text{Tok…...

学习记录-用例设计编写
黑马测试视频记录 目录 一、 软件测试流程 二、测试用例编写格式 1、等价类法 2、边界值分析法 3、 判定表法 4、场景法编辑 5、错误推荐法 一、 软件测试流程 二、测试用例编写格式 1、等价类法 2、边界值分析法 3、 判定表法 4、场景法 5、错误推荐法 时间紧任务重…...

学习工具的一天之(burp)
第一呢一定是先下载 【Java环境】:Java Downloads | Oracle 下来是burp的下载 Download Burp Suite Community Edition - PortSwigger 【下载方法二】关注的一个博主 【BurpSuite 安装激活使用详细上手教程 web安全测试工具】https://www.bilibili.com/video/BV…...

el-tree右键节点动态位置展示菜单;el-tree的节点图片动态根据节点属性color改变背景色;加遮罩层(opacity)
一、el-tree右键节点动态位置展示菜单 关键:@node-contextmenu="handleRightClick"与@node-click=“handleNodeClick” <div class="content"><el-tabs class="tabs" @tab-click="handleClick" v-model="Modal"…...

K8s 1.27.1 实战系列(一)准备工作
一、主机规划与硬件要求 1、节点数量 至少需要 3 台服务器(1 台 Master 节点,2 台 Worker 节点)。本地测试可缩容:若仅用于测试,可缩减为 1 个 Master 和 1 个 Worker,但需注意稳定性风险。2、硬件配置 Master 节点:建议 2 核 CPU、8GB 内存、80GB 硬盘。Worker 节…...

说一下SpringBoot3新特新和JDK17新特性
JDK1.8(Java8)新特性 stream流式编程 流处理 Stream API 提供了对集合数据进行操作的一种高效、简洁的方式。它支持顺序和并行的聚合操作 如:过滤(filter)、排序(sort)、映射(map&…...

Linux系统服务安全检测手记
一:服务器ip暴露ip和端口的安全问题 服务器IP和端口暴露在外网中确实存在一定的安全风险,以下是几个主要的安全问题及相应的缓解措施: ### 主要安全问题 1. **直接攻击**: - 暴露的IP地址和开放的端口可能成为黑客直接攻击的…...

鸿蒙与DeepSeek深度整合:构建下一代智能操作系统生态
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/north 目录 技术融合背景与价值鸿蒙分布式架构解析DeepSeek技术体系剖析核心整合架构设计智能调度系统实现…...

[创业之路-329]:华为铁三角实施的步骤
一、通用过程 华为铁三角实施的步骤主要包括以下几个关键阶段: 1、明确角色与职责 确定铁三角成员:组建由客户经理(AR)、解决方案经理(SR)和交付经理(FR)组成的铁三角团队。制定岗…...

1.15-16-17-18迭代器与生成器,函数,数据结构,模块
目录 15,Python3 迭代器与生成器15-1 迭代器15-1-1 基础知识15-1-2 迭代器与for循环工作原理 15-2 生成器(本质就是迭代器)15-2-1 yield 表达式15-2-2 三元表达式15-2-3 列表生成式15-2-4 其他生成器(——没有元祖生成式——&…...

java面向对象(详细讲解)
第一章 类和对象 1.面向对象的介绍 1.面向过程:自己的事情自己做,代表语言c语言 2.面向对象:自己的事情别人做,代表语言java 3.为啥要使用面向对象思想编程:很多功能别人给我们实现好了,我们只需要拿过…...

代码随想录二刷|图论2
图论 基础知识 1 无向图 (1)度:一个顶点连n条边就度为n (2)权 加权无向图:有边长的无向图 (3)通道:两个顶点之间有一些边和点,并且没有重复的边 路&am…...

毕业项目推荐:基于yolov8/yolov5/yolo11的暴力行为检测识别系统(python+卷积神经网络)
文章目录 概要一、整体资源介绍技术要点功能展示:功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出(xls格式)功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…...

服务器CPU微架构
1、微架构图 前端:预解码、解码、分支预测、L1指令缓存、指令TLB缓存 后端:顺序重排缓存器ROB处理依赖,调度器送到执行引擎 执行引擎:8路超标量,每一路可以进行独立的微操作处理 Port0、1、5、6支持整数、浮点数的加…...

用本地浏览器打开服务器上使用的Tensorboard
文章目录 前言一、Tensorboard的安装二、使用步骤1.服务器上的设置2.在本地打开 总结 前言 最近有使用服务器上的Tensorboard的需求,踩了几个雷,现已在搜索和帮助下解决,总结于此。 一、Tensorboard的安装 pip install tensorboard2.12.0注…...

Nginx或Tengine服务器配置SSL证书
本文将全面介绍如何在Nginx或Tengine服务器配置SSL证书,具体包括下载和上传证书文件,在Nginx上配置证书文件、证书链和证书密钥等参数,以及安装证书后结果的验证。成功配置SSL证书后,您将能够通过HTTPS加密通道安全访问Nginx服务器…...

【基础4】插入排序
核心思想 插入排序是一种基于元素比较的原地排序算法,其核心思想是将数组分为“已排序”和“未排序”两部分,逐个将未排序元素插入到已排序部分的正确位置。 例如扑克牌在理牌的时候,一般会将大小王、2、A、花牌等按大小顺序插入到左边&…...

2安卓开发的主要语言
1. Kotlin(官方首选语言) 定位:Google 官方推荐的首选 Android 开发语言(2019 年起)。 优势: 简洁高效:语法糖减少样板代码(如 data class 自动生成 equals()/hashCode()࿰…...

Python练习(握手问题,进制转换,日期问题,位运算,求和)
一. 握手问题 代码实现 ans0for i in range(1,51):for j in range(i1,51):if i<7 and j<7:continueelse:ans 1print(ans) 这道题可以看成是50个人都握了手减去7个人没握手的次数 答案:1204 二.将十进制整数拆解 2.1门牌制作 代码实现 ans0for i in ra…...