1

我正在使用 Django-rest-framework 和 Django-rest-knox 构建一个带有身份验证实现的 rest API,并且在前端我使用的是 React.js。我想将身份验证令牌安全地存储在前端,我知道最好的方法是使用 httponly cookie,所以我在我的代码中使用了它:

带有 cookie 的 django-rest-knox

from django.contrib.auth import login
from rest_framework import permissions
from rest_framework.authtoken.serializers import AuthTokenSerializer
from knox.views import LoginView as KnoxLoginView


class LoginView(KnoxLoginView):
    permission_classes = (permissions.AllowAny,)

    def post(self, request, format=None):
        serializer = AuthTokenSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        response = super(LoginView, self).post(request, format=None)

        token = response.data['token']
        del response.data['token']

        response.set_cookie(
            'auth_token',
            token,
            httponly=True,
            samesite='strict'
        )

        return response

此代码完美运行,因此它发送一个 Set-Cookie 标头并创建一个 httponly cookie。但问题是,如果 JavaScript 无法访问这些 cookie,我如何使用 Authorization 标头从 react 和 axios 访问受保护的路由。

4

1 回答 1

1
  1. 创建一个高阶组件作为“ProtectedRoute”,仅当用户经过身份验证和授权时才呈现组件。

ProtectedRoute 组件

const ProtectedRoute = ({component:Component, ...rest}) => {
    const [isLoggedIn, setLoggedIn] = useState({loggedIn:'', loaded:false})
    useEffect(async () => {
        const userStatus = await validateUserLoggedIn();
        setLoggedIn((prevState) => {return {loggedIn:userStatus, loaded:true}})
    }, [])

    return(
        <Route {...rest} render={(routerProps) => {
            if(isLoggedIn.loaded){
                if(isLoggedIn.loggedIn ==='success'){
                    return(
                        <Component {...rest} {...routerProps}/>
                    )
                }else{
                    return(
                        <Redirect to={{
                            pathname:'/login',
                            state:{from : routerProps.location}
                        }} />
                    )
                }
            }else{
                return(
                    <Row style={{display: 'flex', justifyContent: 'center'}}>
                      (<CustomLoader />)
                    </Row>
                )
            }
        }}
        />
    )
}


<ProtectedRoute exact path="/admin" component={Admin} />
  1. ProtectedRoute 是一个 HOC 组件,它根据“validateUserLoggedIn”返回值返回组件。有关更多信息,请参阅“react-router-dom”。为路由创建 HOC 的语法如下

伪代码

const ProtectedRoute({component:Component, ...rest}) => {
    return (
        <Route {...rest} render={
            (routerProps) => {
                isUserAuthenticated ?
                (<Component {...rest} {...routerProps} />) :
                "redirect to login or display unauthorized"
            }
        }
    )
}
  1. validateUserLoggedIn 函数使用存储在仅 HTTP cookie 中的凭据进行 API 调用,如果请求被禁止,它将调用刷新端点以获取新的访问令牌并再次发出请求以验证用户是否经过身份验证。

验证用户登录

const validateUserLoggedIn = async () => {
    const loggedIn = {status:''}

    const axiosValidateUserLoggedIn = axios.create(VALIDATEUSERAXIOSCONFIG);

    axiosValidateUserLoggedIn.interceptors.response.use(
        (resp) => {return resp},
        (err) => {
            const originalRequest = err.config;

            const refreshTokenStatus = refreshToken();

            if(refreshTokenStatus === 'success'){
                axios(originalRequest)
            }else{
                window.location.href = '/login';
            }
            // Does this necessary
            return Promise.reject(err)
        }
    )

    await axiosValidateUserLoggedIn.get('userloggedin/')
    .then((resp) => {
        loggedIn.status = resp.data.loggedIn
    })


    console.log(`inside validateUserLoggedIn  - ${loggedIn.status}`)
    return loggedIn.status;
}
  1. 我使用 dj-rest-auth 进行令牌认证。
于 2021-09-11T19:36:03.527 回答