从 flutter 中设置 Firebase 身份验证的自定义声明
Setting custom claims for Firebase auth from flutter
我正在为应用程序使用 Firebase 身份验证,但作为用户创建的一部分,我需要设置一些自定义声明。
我编写了一个云函数来在创建用户时设置声明:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(user => {
let customClaims;
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, {
'https://hasura.io/jwt/claims': {
'x-hasura-default-role': 'user',
'x-hasura-allowed-roles': ['user'],
'x-hasura-user-id': user.uid
}
})
.then(() => {
// Update real-time database to notify client to force refresh.
const metadataRef = admin.database().ref("metadata/" + user.uid);
// Set the refresh time to the current UTC timestamp.
// This will be captured on the client to force a token refresh.
return metadataRef.set({
refreshTime: new Date().getTime()
});
})
.then(() => {
return admin.auth().getUser(user.uid);
})
.then(userRecord => {
console.log(userRecord);
return userRecord.toJSON();
})
.catch(error => {
console.log(error);
});
});
当我将 userRecord 打印到控制台时,我可以看到自定义声明设置正确。
然后我从创建的用户那里得到了令牌,但它似乎没有附加自定义声明。
我正在使用此代码创建用户并在 flutter 中打印声明
Future<FirebaseUser> signUp({String email, String password}) async {
final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
email: email,
password: password,
)).user;
IdTokenResult result = await (user.getIdToken(refresh: true));
print('claims : ${result.claims}');
return user;
}
如果我在 jwt 调试器中检查令牌本身,我可以看到它没有得到自定义声明。
是否我需要一些额外的步骤来尝试在设置声明后获取更新的令牌?
我试过 user.reload()
和 user.getIdToken(refresh: true)
但它们似乎没有帮助。
关于如何获得具有自定义声明的令牌的任何想法?
您显示的代码可能在帐户创建后过早地尝试获取自定义声明。在您调用 auth.createUserWithEmailAndPassword
后,该函数将需要几秒钟的时间才能触发。它异步运行,根本不会阻止用户创建过程。因此,在调用 user.getIdToken(refresh: true)
.
之前,您需要以某种方式等待函数完成
这正是我在 this blog post 中要解决的问题。我提供的解决方案执行以下操作:
- 客户端:创建一个用户
- 客户端:等待在 Firestore 中创建具有用户 UID 的文档
- 服务器:Auth onCreate 函数触发
- 服务器:功能正常工作
- 服务器:最后,函数使用新用户的 UID 将数据写入新文档
- 客户端:数据库侦听器在创建文档时触发
然后,您将在客户端上添加更多步骤以在看到新文档后刷新 ID 令牌。
post中给出的代码适用于web/javascript,但该过程适用于任何客户端。您只需要让客户端等待功能完成,而 Firestore 是中继该信息的便利场所,因为客户端可以实时收听它。
还有 read this post 一种让客户端根据写入 Firestore 文档的声明立即刷新其令牌的方法。
最重要的是,您需要大量代码才能在客户端和服务器之间进行同步。
为了将来参考,我设法根据 Doug 的建议进行了此操作。
这是我的 firebase sdk 管理函数。
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const firestore = admin.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(async user => {
// Check if user meets role criteria:
// Your custom logic here: to decide what roles and other `x-hasura-*` should the user get
let customClaims;
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, {
'https://hasura.io/jwt/claims': {
'x-hasura-default-role': 'user',
'x-hasura-allowed-roles': ['user'],
'x-hasura-user-id': user.uid
}
})
.then(async () => {
await firestore.collection('users').doc(user.uid).set({
createdAt: admin.firestore.FieldValue.serverTimestamp()
});
})
.catch(error => {
console.log(error);
});
});
然后在事情的颤动方面
Future<FirebaseUser> signUp({String email, String password}) async {
final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
email: email,
password: password,
)).user;
currentUser = user;
await waitForCustomClaims();
return user;
}
Future waitForCustomClaims() async {
DocumentReference userDocRef =
Firestore.instance.collection('users').document(currentUser.uid);
Stream<DocumentSnapshot> docs = userDocRef.snapshots(includeMetadataChanges: false);
DocumentSnapshot data = await docs.firstWhere((DocumentSnapshot snapshot) => snapshot?.data !=null && snapshot.data.containsKey('createdAt'));
print('data ${data.toString()}');
IdTokenResult idTokenResult = await (currentUser.getIdToken(refresh: true));
print('claims : ${idTokenResult.claims}');
}
希望这会帮助其他想要做类似事情的人。
我正在为应用程序使用 Firebase 身份验证,但作为用户创建的一部分,我需要设置一些自定义声明。
我编写了一个云函数来在创建用户时设置声明:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(user => {
let customClaims;
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, {
'https://hasura.io/jwt/claims': {
'x-hasura-default-role': 'user',
'x-hasura-allowed-roles': ['user'],
'x-hasura-user-id': user.uid
}
})
.then(() => {
// Update real-time database to notify client to force refresh.
const metadataRef = admin.database().ref("metadata/" + user.uid);
// Set the refresh time to the current UTC timestamp.
// This will be captured on the client to force a token refresh.
return metadataRef.set({
refreshTime: new Date().getTime()
});
})
.then(() => {
return admin.auth().getUser(user.uid);
})
.then(userRecord => {
console.log(userRecord);
return userRecord.toJSON();
})
.catch(error => {
console.log(error);
});
});
当我将 userRecord 打印到控制台时,我可以看到自定义声明设置正确。
然后我从创建的用户那里得到了令牌,但它似乎没有附加自定义声明。
我正在使用此代码创建用户并在 flutter 中打印声明
Future<FirebaseUser> signUp({String email, String password}) async {
final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
email: email,
password: password,
)).user;
IdTokenResult result = await (user.getIdToken(refresh: true));
print('claims : ${result.claims}');
return user;
}
如果我在 jwt 调试器中检查令牌本身,我可以看到它没有得到自定义声明。
是否我需要一些额外的步骤来尝试在设置声明后获取更新的令牌?
我试过 user.reload()
和 user.getIdToken(refresh: true)
但它们似乎没有帮助。
关于如何获得具有自定义声明的令牌的任何想法?
您显示的代码可能在帐户创建后过早地尝试获取自定义声明。在您调用 auth.createUserWithEmailAndPassword
后,该函数将需要几秒钟的时间才能触发。它异步运行,根本不会阻止用户创建过程。因此,在调用 user.getIdToken(refresh: true)
.
这正是我在 this blog post 中要解决的问题。我提供的解决方案执行以下操作:
- 客户端:创建一个用户
- 客户端:等待在 Firestore 中创建具有用户 UID 的文档
- 服务器:Auth onCreate 函数触发
- 服务器:功能正常工作
- 服务器:最后,函数使用新用户的 UID 将数据写入新文档
- 客户端:数据库侦听器在创建文档时触发
然后,您将在客户端上添加更多步骤以在看到新文档后刷新 ID 令牌。
post中给出的代码适用于web/javascript,但该过程适用于任何客户端。您只需要让客户端等待功能完成,而 Firestore 是中继该信息的便利场所,因为客户端可以实时收听它。
还有 read this post 一种让客户端根据写入 Firestore 文档的声明立即刷新其令牌的方法。
最重要的是,您需要大量代码才能在客户端和服务器之间进行同步。
为了将来参考,我设法根据 Doug 的建议进行了此操作。
这是我的 firebase sdk 管理函数。
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const firestore = admin.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(async user => {
// Check if user meets role criteria:
// Your custom logic here: to decide what roles and other `x-hasura-*` should the user get
let customClaims;
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, {
'https://hasura.io/jwt/claims': {
'x-hasura-default-role': 'user',
'x-hasura-allowed-roles': ['user'],
'x-hasura-user-id': user.uid
}
})
.then(async () => {
await firestore.collection('users').doc(user.uid).set({
createdAt: admin.firestore.FieldValue.serverTimestamp()
});
})
.catch(error => {
console.log(error);
});
});
然后在事情的颤动方面
Future<FirebaseUser> signUp({String email, String password}) async {
final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
email: email,
password: password,
)).user;
currentUser = user;
await waitForCustomClaims();
return user;
}
Future waitForCustomClaims() async {
DocumentReference userDocRef =
Firestore.instance.collection('users').document(currentUser.uid);
Stream<DocumentSnapshot> docs = userDocRef.snapshots(includeMetadataChanges: false);
DocumentSnapshot data = await docs.firstWhere((DocumentSnapshot snapshot) => snapshot?.data !=null && snapshot.data.containsKey('createdAt'));
print('data ${data.toString()}');
IdTokenResult idTokenResult = await (currentUser.getIdToken(refresh: true));
print('claims : ${idTokenResult.claims}');
}
希望这会帮助其他想要做类似事情的人。