django和angular.js与身份验证

时间:2021-08-14 12:43:08

I have a web app that's already written in Django, and it is working quite well. I want to add a few views for angular as the plan is to move into that direction. One issue i'm facing is that some of my controllers require login, with django we normally use the @login_required decorator and everything is fine.

我有一个已经用Django编写的Web应用程序,它运行得很好。我想为角度添加一些视图,因为计划是朝着那个方向移动。我面临的一个问题是我的一些控制器需要登录,django我们通常使用@login_required装饰器,一切都很好。

But with angular.js calling the controllers (for api's), the redirect is not happening. I'm assuming I'll have to somehow check if my django user is authenticated directly from angular side. Is there any explanation on how to confirm this on angular? I have been struggling with this and have read the following:

但是当angular.js调用控制器(对于api)时,重定向不会发生。我假设我必须以某种方式检查我的django用户是否直接从有角度的方面进行身份验证。关于如何在角度上确认这个有什么解释吗?我一直在努力解决这个问题并阅读以下内容:

https://docs.angularjs.org/api/ng/service/$http

https://medium.com/@vince_prignano/angular-js-with-django-bde834dbd61e

$routeProvider not triggered after login redirect

登录重定向后未触发$ routeProvider

http://www.django-rest-framework.org/api-guide/authentication/

Basically, I want to confirm, via Angular, that my user is logged in and if not, redirect them to the login page.

基本上,我想通过Angular确认我的用户已登录,如果没有,则将其重定向到登录页面。

EDIT

I'm implementing a request interceptor as shown here:

我正在实现一个请求拦截器,如下所示:

Interceptor not working

拦截器不起作用

However, in django @login_required it's returning the html of the redirecting page. Is there a way to get the URL and forward the user there?

但是,在django @login_required中,它返回重定向页面的html。有没有办法获取URL并转发用户?

5 个解决方案

#1


1  

Add resolve in your $routeProvider as:

在$ routeProvider中添加解决方案:

    $routeProvider 
      .when('/', { 
         templateUrl: '/views/main.html' }) 
      .when('/admin', {
         templateUrl: 'views/admin.html', 
         controller: 'AdminCtrl', 
         resolve: { loggedin: checkLoggedin } }) 
      .when('/login', { 
         templateUrl: 'views/login.html', 
         controller: 'LoginCtrl' }) 
      .otherwise({ redirectTo: '/' }); -

See more at: https://vickev.com/#!/article/authentication-in-single-page-applications-node-js-passportjs-angularjs

有关详细信息,请访问:https://vickev.com/#!/ article /authentication-in-single-page-applications-node-js-passportjs-angularjs

#2


1  

As mentioned in the previous answer, it would be best if your Django back-end can issue a 401 response when login is required. Right now it sounds like it's sending a 302, which you can still observe in the browser if you're making an XHR request. As you've found, using $http interceptors in Angular are a common way of looking for a 401 and sending the user to a login page.

正如前面的回答中所提到的,如果您的Django后端在需要登录时可以发出401响应,那将是最好的。现在它听起来像是在发送302,如果您正在发出XHR请求,您仍然可以在浏览器中观察到它。正如您所发现的,在Angular中使用$ http拦截器是查找401并将用户发送到登录页面的常用方法。

I've taken a different approach: implement a service that abstracts this a bit, via a method called $user.get() - it makes a request to a known endpoint (in my case, /api/users/current) and rejects the returned promise if it sees a 401. In your case you could implement a rejection handler that uses window.location.href to send the user to your dedicated login page

我采取了不同的方法:通过一个名为$ user.get()的方法实现一个抽象这一点的服务 - 它向一个已知端点(在我的例子中,/ api / users / current)发出请求并拒绝如果它看到401,则返回promise。在你的情况下,你可以实现一个拒绝处理程序,它使用window.location.href将用户发送到你的专用登录页面

Disclaimer: I work at Stormpath and we’ve spent a log of time thinking about this :) In my comments above I’m referring to our Stormpath Angular SDK - you can look at this library to see how I’ve solved this problem.

免责声明:我在Stormpath工作,我们花了一段时间思考这个问题:)在上面的评论中,我指的是我们的Stormpath Angular SDK - 你可以看看这个库,看看我是如何解决这个问题的。

#3


1  

When defining my app i'm doing this:

在定义我的应用程序时,我正在这样做:

$httpProvider.interceptors.push('errorInterceptor');

and The code for that is below:

并且代码如下:

app.factory('errorInterceptor', ['$q', '$rootScope', '$location',
    function ($q, $rootScope, $location) {
        return {
            request: function (config) {
                return config || $q.when(config);
            },
            requestError: function(request){
                return $q.reject(request);
            },
            response: function (response) {
                return response || $q.when(response);
            },
            responseError: function (response) {
                if (response && response.status == 302 && response.data.url) {
                    window.location = response.data.url;
                    return;
                }
                return $q.reject(response);
            }
        };
}]);

Basically, we can't use login_required. We have to create a new decorator and provide a 302 status with a url.

基本上,我们不能使用login_required。我们必须创建一个新的装饰器并使用url提供302状态。

#4


1  

If you're making APIs calls via AJAX back to the server, most likely you don't want the response to be redirected to the login page.

如果您通过AJAX将API调用回服务器,则很可能您不希望将响应重定向到登录页面。

I have the same use case and made my own decorator to return a 403 when the user is not logged in. You may also use 401 instead if you like (I left it commented out).

我有相同的用例,并且当用户没有登录时,我自己的装饰器返回403.如果你愿意,你也可以使用401(我把它留下了注释)。

I use 403 because 401 seems to imply WWW authentication.

我使用403因为401似乎意味着WWW身份验证。

from django.http import HttpResponse, HttpResponseForbidden


def logged_in_or_deny(func):
    def check_request(request, *args, **kwargs):
        if (request.user.is_authenticated()):
            return func(request, *args, **kwargs)
        else:
            return HttpResponseForbidden('You must be logged in')       # 403 Response
            #return HttpResponse('You must be logged in', status=401)    # 401 Response
    return check_request

Then you would protect your view like this:

那你就像这样保护你的观点:

@logged_in_or_deny
def your_view(request):
    # ... your code ...
    return HttpResponse('Your normal response :)')

From Angular, it seems like you already know how to use an interceptor to check the response code and redirect the user accordingly. If you use the 403 or 401, you should check the against the response body just in case you respond with similar errors in the future.

从Angular看来,您似乎已经知道如何使用拦截器来检查响应代码并相应地重定向用户。如果您使用403或401,则应检查响应正文,以防万一您以后回复类似的错误。

While what you already have would work, 302 responses can be used for other reasons. It's better to have an explicit 4xx response rather than a 3xx redirection response since it'll be immediately obvious that it's a client side error (missing authentication).

虽然您已经拥有的功能可以使用,但其他原因可以使用302个响应。最好有一个明确的4xx响应而不是3xx重定向响应,因为很明显它是客户端错误(缺少身份验证)。

#5


0  

You can use Http-Auth-Interceptor. Suppose A view requires login and a user makes a request to the view without login then @login_required decorator returns the response with response code 401. In auth interceptor intercept the status code if status code is 401 then redirect user to the login page.

你可以使用Http-Auth-Interceptor。假设一个视图需要登录,并且用户在没有登录的情况下向视图发出请求,那么@login_required装饰器将返回响应代码为401的响应。在auth拦截器中,如果状态代码为401则截取状态代码,然后将用户重定向到登录页面。

example site: http://witoldsz.github.io/angular-http-auth/

示例站点:http://witoldsz.github.io/angular-http-auth/

#1


1  

Add resolve in your $routeProvider as:

在$ routeProvider中添加解决方案:

    $routeProvider 
      .when('/', { 
         templateUrl: '/views/main.html' }) 
      .when('/admin', {
         templateUrl: 'views/admin.html', 
         controller: 'AdminCtrl', 
         resolve: { loggedin: checkLoggedin } }) 
      .when('/login', { 
         templateUrl: 'views/login.html', 
         controller: 'LoginCtrl' }) 
      .otherwise({ redirectTo: '/' }); -

See more at: https://vickev.com/#!/article/authentication-in-single-page-applications-node-js-passportjs-angularjs

有关详细信息,请访问:https://vickev.com/#!/ article /authentication-in-single-page-applications-node-js-passportjs-angularjs

#2


1  

As mentioned in the previous answer, it would be best if your Django back-end can issue a 401 response when login is required. Right now it sounds like it's sending a 302, which you can still observe in the browser if you're making an XHR request. As you've found, using $http interceptors in Angular are a common way of looking for a 401 and sending the user to a login page.

正如前面的回答中所提到的,如果您的Django后端在需要登录时可以发出401响应,那将是最好的。现在它听起来像是在发送302,如果您正在发出XHR请求,您仍然可以在浏览器中观察到它。正如您所发现的,在Angular中使用$ http拦截器是查找401并将用户发送到登录页面的常用方法。

I've taken a different approach: implement a service that abstracts this a bit, via a method called $user.get() - it makes a request to a known endpoint (in my case, /api/users/current) and rejects the returned promise if it sees a 401. In your case you could implement a rejection handler that uses window.location.href to send the user to your dedicated login page

我采取了不同的方法:通过一个名为$ user.get()的方法实现一个抽象这一点的服务 - 它向一个已知端点(在我的例子中,/ api / users / current)发出请求并拒绝如果它看到401,则返回promise。在你的情况下,你可以实现一个拒绝处理程序,它使用window.location.href将用户发送到你的专用登录页面

Disclaimer: I work at Stormpath and we’ve spent a log of time thinking about this :) In my comments above I’m referring to our Stormpath Angular SDK - you can look at this library to see how I’ve solved this problem.

免责声明:我在Stormpath工作,我们花了一段时间思考这个问题:)在上面的评论中,我指的是我们的Stormpath Angular SDK - 你可以看看这个库,看看我是如何解决这个问题的。

#3


1  

When defining my app i'm doing this:

在定义我的应用程序时,我正在这样做:

$httpProvider.interceptors.push('errorInterceptor');

and The code for that is below:

并且代码如下:

app.factory('errorInterceptor', ['$q', '$rootScope', '$location',
    function ($q, $rootScope, $location) {
        return {
            request: function (config) {
                return config || $q.when(config);
            },
            requestError: function(request){
                return $q.reject(request);
            },
            response: function (response) {
                return response || $q.when(response);
            },
            responseError: function (response) {
                if (response && response.status == 302 && response.data.url) {
                    window.location = response.data.url;
                    return;
                }
                return $q.reject(response);
            }
        };
}]);

Basically, we can't use login_required. We have to create a new decorator and provide a 302 status with a url.

基本上,我们不能使用login_required。我们必须创建一个新的装饰器并使用url提供302状态。

#4


1  

If you're making APIs calls via AJAX back to the server, most likely you don't want the response to be redirected to the login page.

如果您通过AJAX将API调用回服务器,则很可能您不希望将响应重定向到登录页面。

I have the same use case and made my own decorator to return a 403 when the user is not logged in. You may also use 401 instead if you like (I left it commented out).

我有相同的用例,并且当用户没有登录时,我自己的装饰器返回403.如果你愿意,你也可以使用401(我把它留下了注释)。

I use 403 because 401 seems to imply WWW authentication.

我使用403因为401似乎意味着WWW身份验证。

from django.http import HttpResponse, HttpResponseForbidden


def logged_in_or_deny(func):
    def check_request(request, *args, **kwargs):
        if (request.user.is_authenticated()):
            return func(request, *args, **kwargs)
        else:
            return HttpResponseForbidden('You must be logged in')       # 403 Response
            #return HttpResponse('You must be logged in', status=401)    # 401 Response
    return check_request

Then you would protect your view like this:

那你就像这样保护你的观点:

@logged_in_or_deny
def your_view(request):
    # ... your code ...
    return HttpResponse('Your normal response :)')

From Angular, it seems like you already know how to use an interceptor to check the response code and redirect the user accordingly. If you use the 403 or 401, you should check the against the response body just in case you respond with similar errors in the future.

从Angular看来,您似乎已经知道如何使用拦截器来检查响应代码并相应地重定向用户。如果您使用403或401,则应检查响应正文,以防万一您以后回复类似的错误。

While what you already have would work, 302 responses can be used for other reasons. It's better to have an explicit 4xx response rather than a 3xx redirection response since it'll be immediately obvious that it's a client side error (missing authentication).

虽然您已经拥有的功能可以使用,但其他原因可以使用302个响应。最好有一个明确的4xx响应而不是3xx重定向响应,因为很明显它是客户端错误(缺少身份验证)。

#5


0  

You can use Http-Auth-Interceptor. Suppose A view requires login and a user makes a request to the view without login then @login_required decorator returns the response with response code 401. In auth interceptor intercept the status code if status code is 401 then redirect user to the login page.

你可以使用Http-Auth-Interceptor。假设一个视图需要登录,并且用户在没有登录的情况下向视图发出请求,那么@login_required装饰器将返回响应代码为401的响应。在auth拦截器中,如果状态代码为401则截取状态代码,然后将用户重定向到登录页面。

example site: http://witoldsz.github.io/angular-http-auth/

示例站点:http://witoldsz.github.io/angular-http-auth/