如何在 Angular JS 应用程序中处理身份验证

Posted

技术标签:

【中文标题】如何在 Angular JS 应用程序中处理身份验证【英文标题】:How to handle authentication in Angular JS application 【发布时间】:2013-08-19 17:54:46 【问题描述】:

我正在我的 Angular js 应用程序中实现一个身份验证系统。

我的计划如下:

    获取用户信息(登录表单中的姓名和密码) 检查用户是否存在 如果存在服务器响应会话 cookie,前端将重定向到某个页面。 然后用户将执行一些将生成 API 请求的任务 API 请求应包含在步骤 3 中发送的 cookie 信息 服务器检查 cookie 是否生成,如果找到 cookie,则返回 API 请求结果。在我的服务中,我正在做类似的事情
MyApp.service('myAuth', function($http, $q) this.authHeader = null; this.checkAuth = 函数() //做api调用,如果成功设置this.authHeader = response this.isAuthenticaed = function() 这个.authHeader ?返回 this.authHeder :返回 false;

提交登录表单后,我将调用 checkAuth 并从我的服务器取回我的会话 cookie,我如何在进行下一次 REST 调用时添加 cookie 信息,以及当用户在登录后浏览整个应用程序时我确实想要每次检查isAuthenticaed真或假,在Angularjs中,当它导航到另一个页面时,它是否在第一次调用设置为真后重置?我的方法 1-6 好还是你有什么具体建议? 顺便说一句,我检查了以前的条目,但这些不是我想知道的。

【问题讨论】:

检查这个问题about auth 检查用户是否通过身份验证...您的服务器端需要返回 401 请求并重定向到登录页面。要检查这一点,你不能在 $http 上放置一个拦截器来监听这个 HTTP 401 响应。 【参考方案1】:

我不确定你的后端,但我会这样做

创建一个单独的登录页面(专用 url 不是角度子视图或 模态对话框)。 如果用户未通过身份验证重定向到此登录 页。这是通过服务器重定向完成的。此页面可能会或可能不会使用 角度框架,因为它只涉及发送用户\密码到 服务器。 从登录页面发出 POST(不是 AJAX 请求),并在服务器上进行验证。 在服务器上设置身份验证 cookie。 (不同框架的做法不同。ASP.Net 设置表单身份验证 cookie。) 用户通过身份验证后,将用户重定向到实际的 Angular 应用并加载其所有组件。

这节省了在 Angular 中管理客户端身份验证所需的任何代码。如果用户登陆此页面,则他已通过身份验证并拥有 cookie。

此外,默认浏览器行为是在每次请求时发送与域关联的所有 cookie,因此您不必担心 Angular 是否发送了一些 cookie。

【讨论】:

这是一个非常好的建议,不仅简化了流程,而且开辟了获得更好性能的新机会。如果有人对上述回答方法感兴趣,请查看ng-conf video 关于这个主题。 @Nobita 精彩视频 在 Angular 中,我可能会在不刷新页面的情况下加载许多视图。使用 Angular 如何在不重新加载页面的情况下检查会话? 当您在 Angular 应用程序中会话到期时会出现问题。而且您不想离开登录网址而失去应用程序的状态。【参考方案2】:

我使用 http-auth-interceptor。 http://ngmodules.org/modules/http-auth-interceptor

在我的后端 (asp.net mvc) 中,我构建了一个简单的身份验证服务,如果用户未通过身份验证,则返回一个 http 错误 401。 然后我在 SPA 站点中使用登录视图处理错误。

【讨论】:

我正在使用拦截器添加身份验证后的cookie来调用REST请求,我不清楚的一件事。注销应该如何工作。我将会话数据(cookie)保存到文件中,当用户发送任何新请求时,我会检查保存的 cookie。当用户发送注销请求时,我是否需要删除 cookie? 我在服务器端使用 ASP.NET MVC,并修改了表单身份验证。在注销时,我的客户端向服务器发送注销请求,服务器会删除身份验证 cookie。 这个模块是最好的选择,原始博客文章解释了如何在单页应用程序中使用 /login 或 /logout 路由不再有意义(尽管它在后端)。刚开始使用 http-auth-interceptor 并看到它做什么/不做什么 - 所以从整体方法的角度来看,这个答案似乎是最好的,但没有涵盖登录流程的所有方面(从 spa/前端到后端并返回,失败和成功)。 frederiknakstad.com/… 提供了很多缺失的细节。【参考方案3】:

前面的答案提出的想法会奏效,但我认为它们有点矫枉过正。你不需要这么复杂的东西。

如何在进行下一次 REST 调用时添加 cookie 信息

$httpProvider中默认打开withCredentials,如下所示:

app.config(['$httpProvider', function($httpProvider) 
    $httpProvider.defaults.withCredentials = true;
]);

然后从与 CORS 相关的标头中删除通配符(如果有的话),并在服务器端设置允许凭据。就我而言,使用 Python + Flask + Flask-Restful,非常简单,看起来像这样:

import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.decorators = [cors.crossdomain(origin='http://localhost:8100', credentials=True)]

现在 cookie 将由浏览器自动且透明地设置和返回。有关详细信息,请参阅这些主题:

$http response Set-Cookie not accessible Angularjs $http does not seem to understand "Set-Cookie" in the response

当用户在登录后浏览整个应用程序时,我确实想检查每次 isAuthenticaed 是真是假

如上所述,如果身份验证会话过期或被删除,则让服务器返回 401,并在 Angular 中使用 $httpInterceptor 像这样捕获:

app.config(function($httpProvider) 
    var interceptor =
        function($q, $rootScope) 
            return 
                'response': function(response) 
                    return response;
                 ,
                'responseError': function(rejection) 
                    if (rejection.status==401) 
                        // Modify this part to suit your needs.
                        // In my case I broadcast a message which is
                        // picked up elsewhere to show the login screen.
                        if (!rejection.config.url.endsWith('/login'))
                        
                            $rootScope.$broadcast('auth:loginRequired');
                        
                    

                    return $q.reject(rejection)
                 
            
        ;

    $httpProvider.interceptors.push(interceptor);
);

【讨论】:

为什么要去掉通配符?请解释一下。【参考方案4】:

(披露:我是 UserApp 的开发者之一)

您可以为此使用第三方服务UserApp,以及AngularJS module。

查看getting started guide,或拨打course on Codecademy。以下是其工作原理的一些示例:

带有错误处理的登录表单:

<form ua-login ua-error="error-msg">
    <input name="login" placeholder="Username"><br>
    <input name="password" placeholder="Password" type="password"><br>
    <button type="submit">Log in</button>
    <p id="error-msg"></p>
</form>

使用user服务访问用户信息:user.current.email

或者在模板中:&lt;span&gt; user.email &lt;/span&gt;

带有错误处理的注册表单:

<form ua-signup ua-error="error-msg">
    <input name="first_name" placeholder="Your name"><br>
    <input name="login" ua-is-email placeholder="Email"><br>
    <input name="password" placeholder="Password" type="password"><br>
    <button type="submit">Create account</button>
    <p id="error-msg"></p>
</form>

ua-is-email表示用户名与邮箱相同。

如何指定哪些路由应该是公开的,哪些路由是登录表单:

$routeProvider.when('/login', templateUrl: 'partials/login.html', public: true, login: true);
$routeProvider.when('/signup', templateUrl: 'partials/signup.html', public: true);

.otherwise() 路由应设置为您希望用户在登录后重定向到的位置。示例:

$routeProvider.otherwise(redirectTo: '/home');

退出链接:

&lt;a href="#" ua-logout&gt;Log Out&lt;/a&gt;

隐藏仅在登录时才可见的元素:

&lt;div ng-show="user.authorized"&gt;Welcome user.first_name !&lt;/div&gt;

要对您的后端服务进行身份验证,只需使用user.token() 获取会话令牌并将其与 AJAX 请求一起发送。在后端,使用UserApp API 来检查令牌是否有效。

如果您需要任何帮助,请告诉我 :)

【讨论】:

以上是关于如何在 Angular JS 应用程序中处理身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在 angular.js 中使用令牌管理身份验证?

如何在同一个 Angular JS 应用程序中使用具有不同身份验证标头的不同 API

如何使基本身份验证作为 Angular JS/Spring 启动应用程序中 keycloak 的替代品

在 Angular 6 + 节点 js 中使用令牌的身份验证问题

如何使用 Spring Boot + Angular 处理外部 OAuth2 身份验证

如何在没有登录表单的情况下将摘要身份验证与 asp.net web api 和 angular js 一起使用?