KGC*_*beX 10 node.js firebase-authentication google-cloud-functions firebase-admin
我需要 Google 登录才能使用 Firebase 应用程序,为了完成此操作,我使用了多个来源:
当尝试在生产环境中登录 Google 帐户时,执行下面的代码验证函数时会出现以下错误:
admin
.auth()
.verifySessionCookie(sessionCookie, true /** checkRevoked */)
.then((decodedClaims) => {
log("Decode success");
// inbetween checks
log("Successfully decoded and authenticated");
next();
})
.catch((error) => {
log("Error authenticating"); < ---- THIS IS THE PROBLEM
...
});
Run Code Online (Sandbox Code Playgroud)
此错误仅在生产(即部署到 Firebase)时发生。当使用仅模拟托管和功能的 firebase 模拟器进行本地测试时(auth、firestore、数据库等都是生产环境),登录成功。部署时,登录失败并出现以下错误。
错误:
解码 Firebase 会话 cookie 失败。确保您传递了代表会话 cookie 的整个字符串 JWT。有关如何检索会话 cookie 的详细信息,请参阅https://firebase.google.com/docs/auth/admin/manage-cookies 。
以下是所执行的步骤/操作的高级概述
所执行操作的步骤概述
1. Visit any page e.g. /login
2. Click sign in with Google, execute the popup provider (see [here][3])
2.
1. Sign in with Google account
2. Send token to firebase functions for verification i.e. `POST /sessionLogin`
3. Receive response (assume 200 OK)
4. Redirect to authenticated URL
Run Code Online (Sandbox Code Playgroud)
错误出现在最后一步,即4
使用firebase 网站上的示例/sessionLogin代码成功创建会话后会出现此错误:
const auth = admin.auth();
auth.verifyIdToken(idToken).then(value => {
debug("Token verified")
return auth.createSessionCookie(idToken, {expiresIn})
.then((sessionCookie) => {
// Set cookie policy for session cookie.
const options = {maxAge: expiresIn, httpOnly: true, secure: true};
res.cookie('session', sessionCookie, options);
// res.json(JSON.stringify({status: 'success'}));
res.status(200).send("OK");
}).catch((error) => {
debug(error);
res.status(401).send('UNAUTHORIZED REQUEST!');
});
}).catch(reason => {
debug("Unable to verify token");
debug(reason);
res.status(401).send('INVALID TOKEN!');
});
Run Code Online (Sandbox Code Playgroud)
日志以 a 响应Token verified,并将状态 200 发送到客户端。
然后,客户端重定向到经过身份验证的 URL /user/dashboard,该 URL 执行身份验证检查(见下文),该检查失败并重定向回/login:
const authenticate = (req, res, next) => {
log("Authenticating");
// source: https://firebase.google.com/docs/auth/admin/manage-cookies#verify_session_cookie_and_check_permissions
const sessionCookie = req.cookies.session || '';
// Verify the session cookie. In this case an additional check is added to detect
// if the user's Firebase session was revoked, user deleted/disabled, etc.
return admin
.auth()
.verifySessionCookie(sessionCookie, true /** checkRevoked */)
.then((decodedClaims) => {
log("Decode success");
// inbetween checks
log("Successfully decoded and authenticated");
next();
})
.catch((error) => {
log("Error authenticating");
if(error.errorInfo && error.errorInfo.code && error.errorInfo.code === "auth/argument-error") {
debug(error.errorInfo.message);
res.redirect('/user/login');
return;
}
debug(error);
// Session cookie is unavailable or invalid. Force user to login.
req.flash("message", [{
status: false,
message: "Invalid session, please login again!"
}])
res.redirect('/user/login');
});
};
Run Code Online (Sandbox Code Playgroud)
这是 Express 应用程序的中间件:
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://my-company-default-rtdb.firebaseio.com",
storageBucket: "gs://my-company.appspot.com"
});
const app = express();
app.use(cors({origin: true}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(morgan('dev'));
app.use(cookieParser('0000-0000-0000-0000-0000'))
app.set('trust proxy', 1) // trust first proxy
// Attach CSRF token on each request.
app.use(attachCsrfToken('/', 'csrfToken', (Math.random()* 100000000000000000).toString()));
app.use(session({
secret: '0000-0000-0000-0000-0000',
resave: false,
name: '__session',
store: new FirebaseStore({
database: admin.database()
}),
}));
app.use(flash());
app.use(authenticate);
// routes
exports.app = functions.https.onRequest(app);
Run Code Online (Sandbox Code Playgroud)
1:12:02.796 PM app函数开始执行
1:12:02.910 PM 应用程序身份验证
1:12:02.910 PM 应用程序尝试验证会话烹饪
1:12:02.910 PM 应用Cookie:{}
1:12:02.911 PM 应用程序身份验证时出错
1:47:41.905 PM 应用程序身份验证/参数错误
1:12:02.911 PM [app]解码 Firebase 会话 cookie 失败。确保您传递了代表会话 cookie 的整个字符串 JWT。 有关如何检索会话 cookie 的详细信息,请参阅https://firebase.google.com/docs/auth/admin/manage-cookies 。
1:12:02.937 PM [app]函数执行花费了 141 毫秒,完成状态代码:302
更新
调用后端进行身份验证:
const postIdTokenToSessionLogin = (idToken, csrfToken) => {
return axios({
url: "/user/sessionLogin",
method: "POST",
data: {
idToken: idToken,
csrfToken: csrfToken,
},
}).then(value => {
console.log(value);
if(value.status === 200) {
window.location.assign("/user/dashboard");
}
}).catch(reason => {
console.error(reason);
alert("Failed to login");
});
}
Run Code Online (Sandbox Code Playgroud)
客户端调用:
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then(async value => {
firebase.auth().currentUser.getIdToken().then(idToken => {
// const idToken = value.credential.idToken;
const csrfToken = getCookie('_csrf');
return postIdTokenToSessionLogin(idToken, csrfToken);
}).catch(reason => {
console.error("Failed to get current user token");
alert(reason.message);
});
})/*.then(value => {
window.location.assign("/user/dashboard")
})*/.catch((error) => {
console.error("Failed to sign in with Google");
alert(error.message);
});
Run Code Online (Sandbox Code Playgroud)
更新2:
使用以下内容更新了客户端 axios 请求,还添加了额外的req.cookies日志记录
return axios({
url: "/user/sessionLogin",
method: "POST",
withCredentials: true,
data: {
idToken: idToken,
csrfToken: csrfToken,
},
})
Run Code Online (Sandbox Code Playgroud)
额外的日志记录:
4:43:23.493 PM app函数开始执行
4:43:23.501 PM 应用程序身份验证
4:43:23.501 PM 应用程序创建会话
4:43:23.502 PM app /sessionLogin Cookies: {"csrfToken":"19888568527706150","session":"eyJhbGciOiJSUzI1NiIsImtpZCI6InRCME0yQSJ9.eyJpc3MiOiJodHRwczovL3Nlc3Npb24uZmlyZWJ..."}
4:43:23.503 PM 应用令牌已验证
4:43:23.503 PM 应用程序{"name":redacted ,"picture":"","iss":"","aud":"",...}
4:43:23.503 PM 应用==============
4:43:23.503 PM 应用程序/sessionLogin#verifyIdToken Cookies: {"csrfToken":"19888568527706150","session":"eyJhbGciOiJSUzI1NiIsImtpZCI6InRCME0yQSJ9.eyJpc3MiOiJodHRwczovL3Nlc3Npb24uZmlyZ王杰……”}
4:43:23.634 PM 应用程序/sessionLogin#createSessionCookie Cookies: {"csrfToken":"19888568527706150","session":"eyJhbGciOiJSUzI1NiIsImtpZCI6InRCME0yQSJ9.eyJpc3MiOiJodHRwczovL3Nlc3N..."}
4:43:23.634 PM 应用程序Cookie:
4:43:23.634 PM 应用程序“eyJhbGciOiJSUzI1NiIsImtpZCI6InRCME0yQSJ9.eyJpc3MiOiJodHRwczovL3Nlc3Npb24uZmlyZWJhc2UuZ29vZ...”
4:43:23.634 PM 应用==============
4:43:23.643 PM 应用程序[0mPOST /user/sessionLogin [32m200[0m 139.036 ms - 2[0m
4:43:23.643 PM app函数执行花费了 150 毫秒,完成状态代码:200
4:43:24.131 PM app函数开始执行
4:43:24.153 PM 应用程序身份验证
4:43:24.153 PM 应用程序尝试验证会话烹饪
4:43:24.153 PM 应用Cookie:{}
更新3
完全重写启用的 API 和 NodeJS 访问,如下所示firebase.json:
{
"database": {
"rules": "database.rules.json"
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"site": "my-company-admin-portal",
"public": "public",
"rewrites": [
{
"source": "/api/**",
"function": "api"
},
{
"source": "**",
"function": "app"
}
],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
"storage": {
"rules": "storage.rules"
},
"emulators": {
"auth": {
"port": 9099
},
"functions": {
"port": 5001
},
"database": {
"port": 9000
},
"hosting": {
"port": 5000
},
"storage": {
"port": 9199
},
"ui": {
"enabled": true
}
}
}
Run Code Online (Sandbox Code Playgroud)
sessionCookie未定义,如问题中提供的代码所示。
// Authenticate middleware right now
const authenticate = (req, res, next) => {
log("Authenticating");
// No sessionCookie declared
return admin
.auth()
.verifySessionCookie(sessionCookie, true /** checkRevoked */)
// undefined passed here ^^^
}
Run Code Online (Sandbox Code Playgroud)
createSessionCookie您必须传递您在方法中使用后设置的cookie,verifySessionCookie如下所示:
// updated authenticate middleware
const authenticate = async (req, res, next) => {
try {
log("Authenticating");
// Read the value of cookie here
const sessionCookie = req.cookies.session
// Return unauthorized error if cookie is absent
if (!sessionCookie) return res.sendStatus(401)
const decodedClaims = await admin.auth().verifySessionCookie(sessionCookie, true)
// cookie verified, continue
} catch (e) {
console.log(e)
return res.send("An error occurred")
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
916 次 |
| 最近记录: |