最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

如何刷新Firebase会话Cookie

IT培训 admin 6浏览 0评论

如何刷新Firebase会话Cookie

我正在使用Node.js / Express.js为后端开发一个Web应用程序,我使用Firebase进行用户身份验证,并管理用户注册等我使用Firebase Admin SDK。

当用户想要登录时,我使用Firebase Client SDK签名,如下所示:

// Handling User SignIn
$('#signin').on('click', function(e){
    e.preventDefault();

    let form = $('#signin-form'),
        email = form.find('#email').val(),
        pass = form.find('#password').val(),
        errorWrapper = form.find('.error-wrapper');

    if(email && pass){
        firebase.auth().signInWithEmailAndPassword(email, pass)
            .catch(err => {
                showError(errorWrapper, err.code)
            });
    }else {
        showError(errorWrapper, 'auth/required');
    }
});

在此代码下方,我设置了一个观察者来监视用户何时成功登录。成功登录后,我获得了一个Firebase ID令牌,我将其发送到服务器上的端点,以便将其交换为具有相同声明的会话cookie ID令牌,因为后者在1小时后到期。

// POST to session login endpoint.
let postIdTokenToSessionLogin = function(url, idToken, csrfToken) {
    return $.ajax({
        type: 'POST',
        url: url,
        data: {
            idToken: idToken,
            csrfToken: csrfToken
        },
        contentType: 'application/x-www-form-urlencoded'
    });
};

// Handling SignedIn Users 
firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        user.getIdToken().then(function(idToken) {
            let csrfToken = getCookie('csrfToken');
            return postIdTokenToSessionLogin('/auth/signin', idToken, csrfToken)
                .then(() => {
                        location.href = '/dashboard';
                    }).catch(err => {
                        location.href = '/signin';
                    });
                });
        });
    } else {
        // No user is signed in.
    }
});

在服务器上登录端点如下所示:

// Session signin endpoint.
router.post('/auth/signin', (req, res) => {
    // Omitted Code...
    firebase.auth().verifyIdToken(idToken).then(decodedClaims => {
        return firebase.auth().createSessionCookie(idToken, {
            expiresIn
        });
    }).then(sessionCookie => {
        // Omitted Code...
        res.cookie('session', sessionCookie, options);
        res.end(JSON.stringify({
            status: 'success'
        }));
    }).catch(err => {
        res.status(401).send('UNAUTHORIZED REQUEST!');
    });
});

我创建了一个中间件来验证用户会话cookie,然后让他访问受保护的内容,如下所示:

function isAuthenticated(auth) {
    return (req, res, next) => {
        let sessionCookie = req.cookies.session || '';
        firebase.auth().verifySessionCookie(sessionCookie, true).then(decodedClaims => {
            if (auth) {
                return res.redirect('/dashboard')
            } else {
                res.locals.user = decodedClaims;
                next();
            }
        }).catch(err => {
            if (auth) next();
            else return res.redirect('/signin')
        });
    }
}

为了在视图上显示用户信息,我在res.locals.user变量上设置了解码的声明并将其传递给下一个中间件,在那里我渲染视图并像这样传递该变量。

router.get('/', (req, res) => {
    res.render('dashboard/settings', {
        user: res.locals.user
    });
});

到目前为止一切都很好,现在问题发生在用户访问他的仪表板以更改他的信息(姓名和电子邮件)之后,当他将具有他的名字和电子邮件的表单提交到服务器上的端点时,我使用Firebase更新他的凭据管理员SDK

// Handling User Profile Update
function settingsRouter(req, res) {
    // Validate User Information ...
    // Update User Info
    let displayName = req.body.fullName,
        email = req.body.email
    let userRecord = {
        email,
        displayName
    }
    return updateUser(res.locals.user.sub, userRecord).then(userRecord => {
        res.locals.user = userRecord;
        return res.render('dashboard/settings', {
            user: res.locals.user
        });
    }).catch(err => {
        return res.status(422).render('dashboard/settings', {
            user: res.locals.user
        });
    });
}

现在,当用户提交表单时,视图会更新,因为我将res.locals.user变量设置为新的userRecord,但是一旦刷新页面,视图就会显示旧凭据,因为在对受保护内容的任何get请求之前,中间件isAuthenticated会被执行并且稍后在更新它们之前从会话cookie中获取包含旧用户凭据的用户信息。

到目前为止,这些是我得出的结论以及我尝试做的事情:

  • 如果我希望视图正确呈现,我应该注销并再次登录以获取新的Firebase ID令牌,以创建新的会话cookie,这不是一个选项。
  • 我尝试通过从Admin SDK创建一个新的ID令牌来刷新会话cookie,但它似乎没有此选项可用,我不能通过客户端SDK执行此操作,因为用户已经登录。
  • 存储ID令牌以便稍后在创建会话cookie时使用不是一种选择,因为它们在1小时后过期。

在发布这里之前我用Google搜索了这个问题,所以任何帮助都非常感激。

回答如下:

我正面临着一个与我的应用程序非常相似的场景。我认为答案就在于这些线索。

来自Firebase docs

Firebase Auth为依赖会话cookie的传统网站提供服务器端会话cookie管理。与客户端短期ID令牌相比,此解决方案有几个优点,每次可能需要重定向机制才能在到期时更新会话cookie:

所以他们在这里暗示你想管理会话,它是服务器的生命周期。

第二条线索在docs

假设应用程序正在使用httpOnly服务器端cookie,请使用客户端SDK在登录页面上登录用户。生成Firebase ID令牌,然后通过HTTP POST将ID令牌发送到会话登录端点,使用Admin SDK生成会话cookie。成功时,应从客户端存储中清除状态。

如果查看示例代码,甚至可以使用firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);将持久性显式设置为None以从客户端清除状态

所以他们打算在最初的身份验证之外的客户端没有任何状态。他们明确地清除了这个状态并期望一个httponly cookie,因此客户端无法获取cookie(它实际上只是ID令牌)并使用它来获取新的cookie。

奇怪的是,没有明确的方法来刷新令牌客户端,但确实如此。您只能真正创建具有超长生命周期的会话cookie,并在服务器上决定何时删除cookie或撤消刷新令牌等。

这样就留下了另一个选择:管理状态客户端。有些examples and tutorials只是将ID令牌从客户端发送到cookie中的服务器。 satte位于客户端上,客户端可以使用ID令牌来使用所有firebase功能。服务器可以验证用户身份并使用令牌等。

这种情况应该更好。如果服务器需要踢用户然后它可以删除cookie撤销刷新令牌(确实有点苛刻)。

希望有所帮助。另一种方案是构建自定义令牌,然后您就可以完全控制。

如何刷新Firebase会话Cookie

我正在使用Node.js / Express.js为后端开发一个Web应用程序,我使用Firebase进行用户身份验证,并管理用户注册等我使用Firebase Admin SDK。

当用户想要登录时,我使用Firebase Client SDK签名,如下所示:

// Handling User SignIn
$('#signin').on('click', function(e){
    e.preventDefault();

    let form = $('#signin-form'),
        email = form.find('#email').val(),
        pass = form.find('#password').val(),
        errorWrapper = form.find('.error-wrapper');

    if(email && pass){
        firebase.auth().signInWithEmailAndPassword(email, pass)
            .catch(err => {
                showError(errorWrapper, err.code)
            });
    }else {
        showError(errorWrapper, 'auth/required');
    }
});

在此代码下方,我设置了一个观察者来监视用户何时成功登录。成功登录后,我获得了一个Firebase ID令牌,我将其发送到服务器上的端点,以便将其交换为具有相同声明的会话cookie ID令牌,因为后者在1小时后到期。

// POST to session login endpoint.
let postIdTokenToSessionLogin = function(url, idToken, csrfToken) {
    return $.ajax({
        type: 'POST',
        url: url,
        data: {
            idToken: idToken,
            csrfToken: csrfToken
        },
        contentType: 'application/x-www-form-urlencoded'
    });
};

// Handling SignedIn Users 
firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        user.getIdToken().then(function(idToken) {
            let csrfToken = getCookie('csrfToken');
            return postIdTokenToSessionLogin('/auth/signin', idToken, csrfToken)
                .then(() => {
                        location.href = '/dashboard';
                    }).catch(err => {
                        location.href = '/signin';
                    });
                });
        });
    } else {
        // No user is signed in.
    }
});

在服务器上登录端点如下所示:

// Session signin endpoint.
router.post('/auth/signin', (req, res) => {
    // Omitted Code...
    firebase.auth().verifyIdToken(idToken).then(decodedClaims => {
        return firebase.auth().createSessionCookie(idToken, {
            expiresIn
        });
    }).then(sessionCookie => {
        // Omitted Code...
        res.cookie('session', sessionCookie, options);
        res.end(JSON.stringify({
            status: 'success'
        }));
    }).catch(err => {
        res.status(401).send('UNAUTHORIZED REQUEST!');
    });
});

我创建了一个中间件来验证用户会话cookie,然后让他访问受保护的内容,如下所示:

function isAuthenticated(auth) {
    return (req, res, next) => {
        let sessionCookie = req.cookies.session || '';
        firebase.auth().verifySessionCookie(sessionCookie, true).then(decodedClaims => {
            if (auth) {
                return res.redirect('/dashboard')
            } else {
                res.locals.user = decodedClaims;
                next();
            }
        }).catch(err => {
            if (auth) next();
            else return res.redirect('/signin')
        });
    }
}

为了在视图上显示用户信息,我在res.locals.user变量上设置了解码的声明并将其传递给下一个中间件,在那里我渲染视图并像这样传递该变量。

router.get('/', (req, res) => {
    res.render('dashboard/settings', {
        user: res.locals.user
    });
});

到目前为止一切都很好,现在问题发生在用户访问他的仪表板以更改他的信息(姓名和电子邮件)之后,当他将具有他的名字和电子邮件的表单提交到服务器上的端点时,我使用Firebase更新他的凭据管理员SDK

// Handling User Profile Update
function settingsRouter(req, res) {
    // Validate User Information ...
    // Update User Info
    let displayName = req.body.fullName,
        email = req.body.email
    let userRecord = {
        email,
        displayName
    }
    return updateUser(res.locals.user.sub, userRecord).then(userRecord => {
        res.locals.user = userRecord;
        return res.render('dashboard/settings', {
            user: res.locals.user
        });
    }).catch(err => {
        return res.status(422).render('dashboard/settings', {
            user: res.locals.user
        });
    });
}

现在,当用户提交表单时,视图会更新,因为我将res.locals.user变量设置为新的userRecord,但是一旦刷新页面,视图就会显示旧凭据,因为在对受保护内容的任何get请求之前,中间件isAuthenticated会被执行并且稍后在更新它们之前从会话cookie中获取包含旧用户凭据的用户信息。

到目前为止,这些是我得出的结论以及我尝试做的事情:

  • 如果我希望视图正确呈现,我应该注销并再次登录以获取新的Firebase ID令牌,以创建新的会话cookie,这不是一个选项。
  • 我尝试通过从Admin SDK创建一个新的ID令牌来刷新会话cookie,但它似乎没有此选项可用,我不能通过客户端SDK执行此操作,因为用户已经登录。
  • 存储ID令牌以便稍后在创建会话cookie时使用不是一种选择,因为它们在1小时后过期。

在发布这里之前我用Google搜索了这个问题,所以任何帮助都非常感激。

回答如下:

我正面临着一个与我的应用程序非常相似的场景。我认为答案就在于这些线索。

来自Firebase docs

Firebase Auth为依赖会话cookie的传统网站提供服务器端会话cookie管理。与客户端短期ID令牌相比,此解决方案有几个优点,每次可能需要重定向机制才能在到期时更新会话cookie:

所以他们在这里暗示你想管理会话,它是服务器的生命周期。

第二条线索在docs

假设应用程序正在使用httpOnly服务器端cookie,请使用客户端SDK在登录页面上登录用户。生成Firebase ID令牌,然后通过HTTP POST将ID令牌发送到会话登录端点,使用Admin SDK生成会话cookie。成功时,应从客户端存储中清除状态。

如果查看示例代码,甚至可以使用firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);将持久性显式设置为None以从客户端清除状态

所以他们打算在最初的身份验证之外的客户端没有任何状态。他们明确地清除了这个状态并期望一个httponly cookie,因此客户端无法获取cookie(它实际上只是ID令牌)并使用它来获取新的cookie。

奇怪的是,没有明确的方法来刷新令牌客户端,但确实如此。您只能真正创建具有超长生命周期的会话cookie,并在服务器上决定何时删除cookie或撤消刷新令牌等。

这样就留下了另一个选择:管理状态客户端。有些examples and tutorials只是将ID令牌从客户端发送到cookie中的服务器。 satte位于客户端上,客户端可以使用ID令牌来使用所有firebase功能。服务器可以验证用户身份并使用令牌等。

这种情况应该更好。如果服务器需要踢用户然后它可以删除cookie撤销刷新令牌(确实有点苛刻)。

希望有所帮助。另一种方案是构建自定义令牌,然后您就可以完全控制。

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论