SPA 中使用 JWT 进行 OAuth 登录后处理的最佳实践

问题描述 投票:0回答:1

我开发了一个简单的单页应用程序(SPA)网站,使用 JWT 进行身份验证,并且运行顺利。但是,我在实现 OAuth 登录时遇到了挑战。我希望获得有关处理 OAuth 登录操作的最佳实践的一些指导。

为了提供上下文,这是我所拥有的:

1。使用典型的 id-password 方法登录:

  • 服务器对用户进行身份验证并返回 JWT。
  • 客户端保存JWT如下:
<button onClick={() => {
    const { accessToken, refreshToken } = tryLogin(id, password);
    processLogin(accessToken, refreshToken);
}}>
    Sign in
</button>

没什么特别的。是吗?

2。处理 OAuth 登录:

完成 OAuth 流程后,我不确定如何继续在我的 SPA 应用程序中实际登录用户。这是我在服务器端的内容(类似 Python 的伪代码),我在其中使用 Google 实现了 OAuth:

def redirectUriHandler(c: HttpContext):
    # The user is currently on my redirect-uri:
    #
    # http://localhost:3000/login/oauth2/code/google
    #     ?state=...
    #     &code=...

    googleToken = exchangeToken(c.code)
    email = getUserInfo(googleToken)
    user = registerOrLogin(email)
    accessToken, refreshToken = generateJWT(user)

    # What should I do here? How can the React app save these tokens?

如果我使用session,那就超级简单:只需设置cookie和session存储,完成!

但是由于我使用的是 SPA,我添加了一个客户端路由器(React Router)并创建了一个端点

/afteroauth
,我在其中使用令牌作为查询参数来重定向用户:

 def doOAuthLogin(c: HttpContext):
     googleToken = exchangeToken(c.code)
     email = getUserInfo(googleToken)
     user = registerOrLogin(email)
     accessToken, refreshToken = generateJWT(user)
 
+    c.redirect(f"/afteroauth?accessToken={accessToken}&refreshToken={refreshToken}")

在客户端,我有以下代码来处理此重定向:

// Client Router /afteroauth
function AfterOAuth() {
    const [params] = userParams();

    processLogin(params.get("accessToken"), params.get("refreshToken"));

    window.location = "/";
}

它有效,但我想知道这是否被认为是最佳实践:

  • 仅出于此目的添加客户端路由器并且
  • 在网络历史记录中拥有代币是否安全(我不这么认为)
reactjs oauth jwt single-page-application
1个回答
0
投票

this这样的答案说没有办法,但我相信我至少解决了有关令牌暴露到网络历史记录的问题。

方法是在服务器上创建保存凭证信息很短时间的票证并将票证发送给客户端,最后客户端使用它来获取真正的 JWT。

但是我仍然需要使用客户端路由器。

之前

我通过查询发送了令牌,因此它保留在浏览器的历史记录中。

SERVER                                  CLIENT
====================================    ======================================

response.redirect(
    /afteroauth
        ?accessToken={accessToken}
        &refreshToken={refreshToken}
)

                                        processLogin(
                                            router.getQuery('accessToken')
                                            router.getQuery('refreshToken')
                                        )

之后

现在我通过查询发送票证,以便它保留在浏览器的历史记录中, 但它的有效期只有10秒,而且只能使用一次,所以我相信它是安全的。

客户端使用票证从正文获取 JWT。

SERVER                                  CLIENT
====================================    ======================================

ticket = UUID()

// valid for 10 secound
volatileStore.push(ticket, userId)
response.redirect(
    /afteroauth
        ?ticket={ticket}
)

                                        ticket = router.getQuery('ticket')
                                        await fetch("/exchange/ticket/{ticket}")

ticket = request.query('ticket')
userId = volatileStore.pop(ticket)
response.body(userStore.findById(userId).generateJWT())

                                        jwt = await fetch("/exchange/ticket/{ticket}")
                                        processLogin(jwt)
© www.soinside.com 2019 - 2024. All rights reserved.