簡體   English   中英

在 Django Rest 框架中使用 simplejwt 進行登錄身份驗證,帶有模板和 ajax

[英]Login Authentication with simplejwt in Django Rest Framework with templates and ajax

我正在嘗試使用 Django Rest 框架和模板制作應用程序,而不使用任何前端應用程序。 我按照文檔https://www.django-rest-framework.org/topics/html-and-forms/創建了登錄表單和用戶列表。 提交 forms 並顯示帶有模板的列表時,它工作正常。 但是,當我嘗試從瀏覽器使用simplejwt驗證登錄時,驗證失敗。 身份驗證失敗

然后我環顧四周,發現了這個文檔https://ilovedjango.com/django/rest-api-framework/authentication/tips/working-example-of-jwt-authentication-with-ajax-django-rest-framework/ I can use the ajax post call to get the token and set it to local storage on submit and set the header of another API later from the local storage, but in that case, it is not going to the action="{% url ' user:user-list-list' %}"提交后模板中的表單。 所以它停留在登錄頁面上,並且只點擊令牌/ URL 作為令牌。 當我在 ajax 成功中添加location.href = "{% url 'user:user-list-list' %}"時,它會加載 user_list 但顯示 401 未經授權。

這是我的 user_login.html 模板:

{% load rest_framework %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<h1>User Login</h1>

<form action="{% url 'user:user-list-list' %}" method="POST" id="login">
    {% csrf_token %}
    <div class="form-group ">

        <label>Username</label>


        <input id="username" name="username" class="form-control" type="text" placeholder="Enter Username" value="">


    </div>
    <div class="form-group ">

        <label>Password</label>


        <input id="password" name="password" class="form-control" type="password" placeholder="Enter Password" value="">


    </div>


    <input type="submit" value="Login" id="submit">
</form>
</body>

<script>
    $("#login").submit(function (event) {
        event.preventDefault();
        let formData = new FormData();
        formData.append('username', $('#username').val().trim());
        formData.append('password', $('#password').val().trim());

        $.ajax({
            url: "http://127.0.0.1:8008/token/",
            type: "POST",
            data: formData,
            cache: false,
            processData: false,
            contentType: false,
            success: function (data) {
                // store tokens in localStorage
                window.localStorage.setItem('refreshToken', data['refresh']);
                window.localStorage.setItem('accessToken', data['access']);
            },
            error: function (rs, e) {
                console.error(rs.status);
                console.error(rs.responseText);
            }
        }); // end ajax
    });
</script>

</html>

這是我在views.py中的登錄信息:

# ////////////////////////////////////////////////////
# @DESC            USER LOGIN
# @ROUTE           POST api/login/
# @ACCESS          Public
# ////////////////////////////////////////////////////

class UserLoginView(viewsets.ModelViewSet):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'user_login.html'
    permission_classes = (AllowAny,)
    serializer_class = UserLoginSerializer

    def create(self, request, *args, **kwargs):
        username = request.data['username']
        password = request.data['password']

        try:
            user = User.objects.get(username=username)
            serializer = self.serializer_class(data=request.data)
            serializer.is_valid(raise_exception=True)

            response = {}
            if user.is_active == 1 or user.is_active == True:
                response = {
                    'success': 'True',
                    'statuscode': status.HTTP_200_OK,
                    'status': 'Active',
                    'message': 'User login successful',
                    'token': serializer.data['token'],
                    'error': ''
                }
            elif user.is_active == 2:
                response = {
                    'success': 'True',
                    'statuscode': status.HTTP_400_BAD_REQUEST,
                    'status': 'Blocked',
                    'message': 'User has been blocked',
                    'error': ''
                }
            elif user.is_active == 3:
                response = {
                    'success': 'True',
                    'statuscode': status.HTTP_400_BAD_REQUEST,
                    'status': 'Unverified',
                    'message': 'Please verify your email to login!',
                    'error': ''
                }
            mylog.info(request.data)
            Log.objects.create(
                user_id=user.id,
                date_time=datetime.now(),
                login_date=datetime.now(),
                component='LoginUser',
                ip=request.META.get('REMOTE_ADDR')
                # ip=request.META.get('HTTP_X_REAL_IP')
            )

            status_code = status.HTTP_200_OK

            return Response(response, status=status_code)

        except Exception as e:
            print(e)
            response = {
                'success': False,
                'statuscode': status.HTTP_400_BAD_REQUEST,
                'message': 'Invalid username or password',
                'error': str(e)
            }
            return Response(response)

    def list(self, request):

        try:
            serializer = UserLoginFormSerializer()
            return Response({'serializer': serializer.data})

        except Exception as e:
            print(e)
            response = {
                'success': False,
                'error': str(e)
            }
            return Response(response)

這是我在views.py中的用戶列表:

# /////////////////////////////////////////////////////////////////////////////
# @DESC            USER LIST, USER GET, USER UPDATE
# @ROUTE           GET api/userlist/, GET api/userlist/pk/, PUT api/userlist/pk/
# @ACCESS          Authenticated User
# /////////////////////////////////////////////////////////////////////////////

class UserListView(viewsets.ModelViewSet):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'user_list.html'
    permission_classes = [IsAuthenticated]
    serializer_class = UserSerializer

    def list(self, request, *args, **kwargs):

        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        try:

            response = {
                'success': True,
                'statuscode': status.HTTP_200_OK,
                'data': serializer.data,
                'message': "View users Successful"
            }

            return Response({'response': response})

        except Exception as e:
            print(e)
            response = {
                'success': False,
                'statuscode': status.HTTP_400_BAD_REQUEST,
                'message': 'User list fetch error',
                'menu': 0,
                'error': str(e)
            }
            mylog.error(e)
            return Response(response)

我知道我需要以某種方式獲取用戶列表 API 的 header 中的令牌才能進行身份驗證,但我似乎找不到方法。 這有可能嗎?

根據文檔,我在 user_list.html 的腳本中添加了此代碼,但由於 API 未針對用戶進行身份驗證,因此無法正常工作。

$(document).ready(function () {
        $.ajax({
            url: '{% url 'user:user-list-list' %}',
            headers: {
                'Authorization': `Bearer ${window.localStorage.getItem('accessToken')}`
            },
            type: "GET",
            tokenFlag: true,
            success: function (data) {
                console.log(data);
            },
            error: handleAjaxError
        });

    });

    function handleAjaxError(rs, e) {
        /*
            And if it returns 401, then we call obtainAccessTokenWithRefreshToken() method
            To get a new access token using refresh token.
        */
        if (rs.status == 401) {
            if (this.tokenFlag) {
                this.tokenFlag = false;
                if (obtainAccessTokenWithRefreshToken()) {
                    this.headers["Authorization"] = `Bearer ${window.localStorage.getItem('accessToken')}`
                    $.ajax(this);  // calling API endpoint again with new access token
                }
            }
        } else {
            console.error(rs.responseText);
        }
    }

    function obtainAccessTokenWithRefreshToken() {
        /*
            This method will create new access token by using refresh token.
            If refresh token is invalid it will redirect user to login page
        */
        let flag = true;
        let formData = new FormData();
        formData.append('refresh', window.localStorage.getItem('refreshToken'));
        $.ajax({
            url: 'http://127.0.0.1:8008/token/refresh/',
            type: "POST",
            data: formData,
            async: false,
            cache: false,
            processData: false,
            contentType: false,
            success: function (data) {
                window.localStorage.setItem('accessToken', data['access']);
            },
            error: function (rs, e) {
                if (rs.status == 401) {
                    flag = false;
                    window.location.href = "/user/login/";
                } else {
                    console.error(rs.responseText);
                }
            }
        }); // end ajax
        return flag
    }

在這種方法中,如何對用戶進行身份驗證並使用經過身份驗證的用戶呈現所有其他 Rest API?

您遇到的問題是您正在混合 sessionStorage 和 localStorage。

在 login.html jQuery 代碼中,您使用 localStorage 來存儲 accessToke 和 refreshToken

// store tokens in localStorage
localStorage.setItem('refreshToken', data['refresh']);
localStorage.setItem('accessToken', data['access']);

在 list_users.html 中,您正在嘗試使用sessionStorage訪問令牌

更改此代碼,即返回accessToken null

headers: {
          'Authorization': `Bearer 
           ${window.sessionStorage.getItem('accessToken')}` // accessToken is null
            },

成為這個

headers: {
          'Authorization': `Bearer 
           ${localStorage.getItem('accessToken')}`
            },

現在您可以訪問存儲在 localStorage 中的 accessToken。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM