这是连接Next.js + NextAuth与Django Rest框架API的正确和安全的方式吗?



我一直在使用Django Rest框架开发一个带有自定义后端的Next.js应用程序,主要关注与社交平台(Google, Github等)的身份验证。下面是我想使用的流程:

  1. 让NextAuth为社会认证做繁重的工作。例如,当用户想要登录他/她的Google帐户时,它会返回一个访问令牌和一个id令牌。
  2. 将Google返回的id令牌和访问令牌放入NextAuth会话对象中。
  3. 在前端,在会话对象中使用这两个令牌向DRF后端发出POST请求,后者基本上接受访问令牌和id令牌,并返回访问令牌和刷新令牌。NB。DRF后端设置dj-rest-authdjango-allauth来处理社会认证。DRF后端以HTTPOnly cookie的形式发送回令牌。所以,下次我想向DRF API发出请求时,cookie应该沿着请求传递。

这是正确和安全的,还是我搬起石头砸自己的脚?

上下文代码:

index.tsx

import React, { useEffect } from "react";
import { signIn, signOut, useSession } from "next-auth/client";
import { Typography, Button, Box } from "@material-ui/core";
import { makeUrl, BASE_URL, SOCIAL_LOGIN_ENDPOINT } from "../urls";
import axios from "axios";
axios.defaults.withCredentials = true;
function auth() {
const [session, loading] = useSession();
useEffect(() => {
const getTokenFromServer = async () => {
// TODO: handle error when the access token expires
const response = await axios.post(
// DRF backend endpoint, api/social/google/ for example
// this returns accessToken and refresh_token in the form of HTTPOnly cookies
makeUrl(BASE_URL, SOCIAL_LOGIN_ENDPOINT, session.provider),
{
access_token: session.accessToken,
id_token: session.idToken,
},
);
};
if (session) {
getTokenFromServer();
}
}, [session]);
return (
<React.Fragment>
<Box
display="flex"
justifyContent="center"
alignItems="center"
m={5}
p={5}
flexDirection="column"
>
{!loading && !session && (
<React.Fragment>
<Typography variant="button">Not logged in</Typography>
<Button
variant="outlined"
color="secondary"
onClick={() => signIn()}
>
Login
</Button>
</React.Fragment>
)}
{!loading && session && (
<React.Fragment>
<Typography>Logged in as {session.user.email}</Typography>
<pre>{JSON.stringify(session, null, 2)}</pre>
<Button
variant="outlined"
color="primary"
onClick={() => signOut()}
>
Sign Out
</Button>
</React.Fragment>
)}
</Box>
</React.Fragment>
);
}
export default auth;

api/auth/[...nextauth].ts

import NextAuth from "next-auth";
import { InitOptions } from "next-auth";
import Providers from "next-auth/providers";
import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
import { BASE_URL, SOCIAL_LOGIN_ENDPOINT, makeUrl } from "../../../urls";
import { AuthenticatedUser, CustomSessionObject } from "../../../types";
import { GenericObject } from "next-auth/_utils";
const settings: InitOptions = {
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorizationUrl:
"https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code",
}),
],
secret: process.env.NEXT_AUTH_SECRET,
session: {
maxAge: 6 * 60 * 60, // 6 hours
},
callbacks: {
async signIn(user: AuthenticatedUser, account, profile) {
if (account.provider === "google") {
const { accessToken, idToken, provider } = account;
user.accessToken = accessToken;
user.idToken = idToken;
user.provider = provider;
return true;
}
return false;
},
async session(session: CustomSessionObject, user: AuthenticatedUser) {
session.accessToken = user.accessToken;
session.idToken = user.idToken;
session.provider = user.provider;
return session;
},
async jwt(token, user: AuthenticatedUser, account, profile, isNewUser) {
if (user) {
token.accessToken = user.accessToken;
token.idToken = user.idToken;
token.provider = user.provider;
}
return token;
},
},
};
export default (req: NextApiRequest, res: NextApiResponse) => {
return NextAuth(req, res, settings);
};

我对会话对象是否足够安全以存储令牌的事实感到压力。我还想实现一种机制,在访问令牌到期时使用刷新令牌来刷新访问令牌。

我最终解决了这个问题。我写了一篇两部分的文章,概述了我是如何解决这个问题的,可以在这里和这里找到

相关内容

  • 没有找到相关文章