聊天室原始碼開發,如何簡單的實現掃碼登入功能?
前言
隨著科技的發展,人們登入聊天室原始碼的方式也變的多種多樣,除了藉助第三方賬號登入之外,還可以實現掃碼登入,具體的實現程式碼如下:
實現思路
使用者選擇掃碼登入可以看作是A:聊天室原始碼前端發授權請求,等待app掃碼。
使用者使用app進行掃碼可以看作是B:掃碼進行授權,返回一個臨時Token供二次認證。
使用者在app進行確認登入可以看作是C:進行登入確認,授權使用者在Web端登入。
聊天室原始碼後端在使用者確認登入後返回一個正式Token即可看作是步驟D。
後續前端根據正式Token訪問後臺介面,正式在Web端進行操作即可看作是E和F。
二次認證的原因
之所以在使用者掃碼之後還需要進行再一次的確認登入,而不是直接就登入聊天室原始碼的原因,則是為了使用者安全考慮,避免使用者掃了其他人需要登入的二維碼,在未經確認就直接登入了,導致他人可能會在我們不知道的情況下訪問我們在聊天室原始碼中的資訊。
實現步驟
1、使用者訪問聊天室原始碼,選擇掃碼登入
使用者在選擇聊天室原始碼掃碼登入時,會向後端傳送一個二維碼的生成請求,後端生成UUID,並儲存到Redis(固定有效時間),狀態設定為UNUSED(未使用)狀態,如果Redis快取過期,則為EXPIRE(過期)狀態,聊天室原始碼前端根據後端返回的內容生成二維碼,並設定一個定時器,每隔一段時間根據二維碼的內容中的UUID,向後端傳送請求,獲取二維碼的狀態,更新介面展示的內容。
生成二維碼後端介面:
/**
* 生成二維碼內容
*
* @return 結果
*/
@GetMapping("/generate")
public BaseResult generate() {
String code = IdUtil.simpleUUID();
redisCache.setCacheObject(code, CodeUtils.getUnusedCodeInfo(),
DEFAULT_QR_EXPIRE_SECONDS, TimeUnit.SECONDS);
return BaseResult.success(GENERATE_SUCCESS, code);
}
聊天室原始碼前端獲取內容,生成二維碼:
getToken() {
this.codeStatus = 'EMPTY'
this.tip = '正在獲取登入碼,請稍等'
// 有效時間 60 秒
this.effectiveSeconds = 60
clearInterval(this.timer)
request({
method: 'get',
url: '/code/generate'
}).then((response) => {
// 請求成功, 設定二維碼內容, 並更新相關資訊
this.code = `${HOST}/code/scan?code=${response.data}`
this.codeStatus = 'UNUSED'
this.tip = '請使用手機掃碼登入'
this.timer = setInterval(this.getTokenInfo, 2000)
}).catch(() => {
this.getToken()
})
}
聊天室原始碼後端返回二維碼狀態資訊的介面:
/**
* 獲取二維碼狀態資訊
*
* @param code 二維碼
* @return 結果
*/
@GetMapping("/info")
public BaseResult info(String code) {
CodeVO codeVO = redisCache.getCacheObject(code);
if (codeVO == null) {
return BaseResult.success(INVALID_CODE, StringUtils.EMPTY);
}
return BaseResult.success(GET_SUCCESS, codeVO);
}
聊天室原始碼前端輪詢獲取二維碼狀態:
getTokenInfo() {
this.effectiveSeconds--
// 二維碼過期
if (this.effectiveSeconds <= 0) {
this.codeStatus = 'EXPIRE'
this.tip = '二維碼已過期,請重新整理'
return
}
// 輪詢查詢二維碼狀態
request({
method: 'get',
url: '/code/info',
params: {
code: this.code.substr(this.code.indexOf('=') + 1)
}
}).then(response => {
const codeVO = response.data
// 二維碼過期
if (!codeVO || !codeVO.codeStatus) {
this.codeStatus = 'EXPIRE'
this.tip = '二維碼已過期,請重新整理'
return
}
// 二維碼狀態為為正在登入
if (codeVO.codeStatus === 'CONFIRMING') {
this.username = codeVO.username
this.avatar = codeVO.avatar
this.codeStatus = 'CONFIRMING'
this.tip = '掃碼成功,請在手機上確認'
return
}
// 二維碼狀態為確認登入
if (codeVO.codeStatus === 'CONFIRMED') {
clearInterval(this.timer)
const token = codeVO.token
store.commit('setToken', token)
this.$router.push('/home')
Message.success('登入成功')
return
}
})
}
2、使用手機掃碼,二維碼狀態改變
當用戶使用手機掃碼時(已登入並且為正確的app,否則掃碼會跳轉到聊天室原始碼自定義的宣傳頁),會更新二維碼的狀態為CONFIRMING(待確認)狀態,並在Redis快取中新增使用者名稱及頭像資訊的儲存供前端使用展示,此外還會返回使用者的登入資訊(登入地址、瀏覽器、作業系統)給app展示,同時生成一個臨時Token給app(固定有效時間)。
使用者掃碼時聊天室原始碼的後臺處理:
/**
* 處理未使用狀態的二維碼
*
* @param code 二維碼
* @param token token
* @return 結果
*/
private BaseResult handleUnusedQr(String code, String token) {
// 校驗 app 端訪問傳遞的 token
boolean isLegal = JwtUtils.verify(token);
if (!isLegal) {
return BaseResult.error(AUTHENTICATION_FAILED);
}
// 儲存使用者名稱、頭像資訊, 供前端展示
String username = JwtUtils.getUsername(token);
CodeVO codeVO = CodeUtils.getConfirmingCodeInfo(username, DEFAULT_AVATAR_URL);
redisCache.setCacheObject(code, codeVO, DEFAULT_QR_EXPIRE_SECONDS, TimeUnit.SECONDS);
// 返回登入地址、瀏覽器、作業系統以及一個臨時 token 給 app
String address = HttpUtils.getRealAddressByIp();
String browser = HttpUtils.getBrowserName();
String os = HttpUtils.getOsName();
String tmpToken = JwtUtils.sign(username);
// 將臨時 token 作為鍵, 使用者名稱為內容儲存在 redis 中
redisCache.setCacheObject(tmpToken, username, DEFAULT_TEMP_TOKEN_EXPIRE_MINUTES, TimeUnit.MINUTES);
LoginInfoVO loginInfoVO = new LoginInfoVO(address, browser, os, tmpToken);
return BaseResult.success(SCAN_SUCCESS, loginInfoVO);
}
3、手機確認登入
當用戶在app中點選確認登入時,就會攜帶生成的臨時Token傳送更新狀態的請求,二維碼的狀態會被更新為CONFIRMED(已確認登入)狀態,同時聊天室原始碼後端會生成一個正式Token儲存在Redis中,前端在輪詢更新狀態時獲取這個Token,然後使用這個Token進行登入。
後端處理確認登入的程式碼:
/**
* 處理未待確認狀態的二維碼
*
* @param code 二維碼
* @param token token
* @return 結果
*/
private BaseResult handleConfirmingQr(String code, String token) {
// 使用臨時 token 獲取使用者名稱, 並從 redis 中刪除臨時 token
String username = redisCache.getCacheObject(token);
if (StringUtils.isBlank(username)) {
return BaseResult.error(AUTHENTICATION_FAILED);
}
redisCache.deleteObject(token);
// 根據使用者名稱生成正式 token並儲存在 redis 中供前端使用
String formalToken = JwtUtils.sign(username);
CodeVO codeVO = CodeUtils.getConfirmedCodeInfo(username, DEFAULT_AVATAR_URL, formalToken);
redisCache.setCacheObject(code, codeVO, DEFAULT_QR_EXPIRE_SECONDS, TimeUnit.SECONDS);
return BaseResult.success(CONFIRM_SUCCESS);
}
以上便是“聊天室原始碼開發,掃碼登入的簡單實現”的全部內容,希望對大家有幫助。
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理
原文連結:https://blog.csdn.net/qq_41698074/article/details/120405575