如何解决在 Wear OS 上进行 Firebase 授权的最佳实践 选项 1:短期代币交换选项 2:PKCE
我正在 Wear OS 上为连接到 Android 设备的随附应用实施 firebase 实时数据库,我想知道在 Wear 手表上对用户进行身份验证的最佳做法是什么。在小手表屏幕上输入电子邮件和密码不是很方便。是否可以通过 Wear os 数据层传递 firebase 授权令牌?如果可以,您将如何使用来自 Android 设备的令牌在 Wear 手表上对用户进行身份验证?
谢谢, 唐尼
解决方法
文档涵盖了您可以使用的 different authentication approaches。
最终,您至少需要一种基于网络的方法来验证手表的身份,因为您无法保证用户会安装您的配套应用或手表未连接到 iOS 设备。
您有两种可用的方法(我能想到):
选项 1:短期代币交换
在此方法中,您执行以下步骤:
- 提示用户打开登录网页或打开配套应用(或发送
RemoteIntent
为他们打开) - 通过身份验证后,调用创建身份验证代码(长度约为 5-6 个字母数字字符)的 Cloud Function,并将其安全地存储在您选择的数据库中,有效期为 1 到 2 分钟。
- 让用户直接在手表上输入代码(或使用数据层将其发送到手表)。
- 将代码发送到另一个 Cloud Functions 函数以将其交换为 Firebase ID 令牌。
const functions = require('firebase-functions');
const sha256 = (s) => require('crypto').createHash('sha256').update(s).digest('base64');
const lazyFirebaseAdmin = () => {
const admin = require('firebase-admin');
try {
admin.app();
} catch {
admin.initializeApp();
}
return admin;
}
const createUserAuthCode = async (uid) => {
const chars = "0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; // omitted O,I,l
let code = "",charsLen = chars.length;
for (let i=0; i<6; i++)
code += chars[Math.floor(Math.random() * charsLen)];
const encoded = sha256(code);
await lazyFirebaseAdmin()
.firestore()
.collection('_server/auth/userCodes')
.doc(encoded)
.create({
created: admin.firestore.FieldValue.serverTimestamp(),uid
});
return code;
}
const validateUserAuthCode = async (code) => {
const encoded = sha256(code);
const codeRef = lazyFirebaseAdmin()
.firestore()
.collection('_server/auth/userCodes')
.doc(encoded);
const snapshot = await codeRef.get();
if (!snapshot.exists)
return null; // not found
const { uid,created } = snapshot.data();
await codeRef.delete();
if (created.toMillis() < Date.now() - (2 * 60 * 1000)) {
return null; // too old
}
return uid || null;
}
const getDeviceCode = functions.https.onCall(async (data,context) => {
if (context.app === undefined) { // If you want to use Firebase App Check to mitigate abuse
throw new HttpsError(
'failed-precondition','Unrecognized caller');
}
if (!context.auth) {
throw new HttpsError(
'failed-precondition','You must be authenticated to request a device code');
}
try {
return {
code: await createUserAuthCode(context.auth.uid)
};
} catch (error) {
throw new HttpsError(
'unknown','Couldn\'t generate device code',{ message: error.code || error.message }
);
}
});
const exchangeDeviceCode = functions.https.onRequest(async (req,res) => {
if (req.method !== "GET") {
console.log("Rejected unexpected " + req.method + " request");
res.status(405)
.set("Allow","GET")
.end();
return;
}
const code = req.query.code;
if (typeof code !== "string") {
res.status(400)
.json({ message: "Missing code param" });
return;
}
try {
const uid = await validateUserAuthCode(code);
const token = await admin.auth()
.createCustomToken(uid,{
isDeviceToken: true // by having this,you can prevent the watch
// auth tokens from doing privileged actions
});
const response = await fetch({
url: "https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=[API_KEY]",// TODO: Replace with Web API key
method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ token,returnSecureToken: true })
});
// idToken - Firebase ID token (access token)
// refreshToken - refresh token for this device authentication token
// expiresIn - number of seconds to ID token expiry
res
.status(response.status)
.set("Content-Type","application/json")
.send(response.text());
} catch (err) {
res.status(500)
.json({ error: "Encountered unexpected error" });
}
});
在客户端,您可以使用以下任一方法调用第一个函数(登录后):
// Java
var getDeviceCodeFunc = FirebaseFunctions.getInstance().getHttpsCallable("getDeviceCode")
getDeviceCodeFunc.call()
.addOnCompleteListener({ task ->
if (task.isSuccessful()) {
// got code!
} else {
// failed!
}
});
// Web/JavaScript
const getDeviceCode = firebase.functions().httpsCallable("getDeviceCode");
const code = await getDeviceCode();
然后一旦用户输入代码,将其发送给
GET https://us-central1-[PROJECT_ID].cloudfunctions.net/exchangeDeviceCode?code=[TYPED_CODE]
选项 2:PKCE
在此方法中,您执行以下步骤:
- [观看] 开始
sendAuthorizationRequest()
流程 - [网页] 验证用户(如果需要)并请求连接设备的权限
- [Cloud Function] 解析上一步的允许/拒绝请求并为该用户生成自定义身份验证令牌
- [Cloud Function] 将自定义身份验证令牌交换为 Firebase ID 令牌并使用 GET 参数
https://wear.googleapis.com/3p_auth/com.your.package.name
和accessToken
重定向到refreshToken
。 - [观看] 解析响应
注意:这对于您正在尝试做的事情来说可能有点矫枉过正。但是,如果您真的不希望有人必须在手表上输入代码,则可以选择使用它。您可以使用 oauth2-server
来代理发布 Firebase ID 令牌(访问令牌)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。