AngularJS:在单页应用程序中使用身份验证的基本示例
Posted
技术标签:
【中文标题】AngularJS:在单页应用程序中使用身份验证的基本示例【英文标题】:AngularJS: Basic example to use authentication in Single Page Application 【发布时间】:2013-04-14 21:57:54 【问题描述】:我是 AngularJS 的新手,通过他们的教程并有所了解。
我已经为我的项目准备好了一个后端,其中每个 REST
端点都需要进行身份验证。
我想做的事
a.) 我想为我的项目创建一个页面http://myproject.com
。
b.) 一旦用户在浏览器中点击 URL,根据用户是否登录,他会在同一 URL http://myproject.com
下显示主页/视图或登录页面/视图。
c.) 如果用户没有登录,它会填写表单并且服务器在会话中设置一个USER_TOKEN
,因此所有对端点的进一步请求都将基于USER_TOKEN
进行身份验证
我的困惑
a.) 如何使用 AngularJS 处理客户端身份验证?我看到here 和here 但不明白如何使用它们
b.) 如何根据用户是否登录到相同的 url http://myproject.com
来向用户呈现不同的视图
我是第一次使用 angular.js,我真的很困惑如何开始。非常感谢任何建议和/或资源。
【问题讨论】:
请看下面的文章frederiknakstad.com/… @MichaelCalkins 只是放置一个链接是没有建设性的。您至少应该说明链接将提供什么。 我的 b:AngularJS 访问控制和身份验证coderwall.com/p/f6brkg OAuth 团队为此提供了一个很棒的库 andreareginato.github.io/oauth-ng 【参考方案1】:我喜欢这种方法并在服务器端实现它,而无需在前端做任何与身份验证相关的事情
我在最新应用上的“技术”是……客户并不关心 授权。应用程序中的每一件事都需要先登录,所以 服务器总是提供登录页面,除非现有用户是 在会话中检测到。如果 session.user 被找到,服务器只是 发送 index.html。巴姆:-o
查找“Andrew Joslin”的评论。
https://groups.google.com/forum/?fromgroups=#!searchin/angular/authentication/angular/POXLTi_JUgg/VwStpoWCPUQJ
【讨论】:
如果它是一个 web api?我猜我没有得到你的答案:( 如果要显示用户名怎么办?或者,如果您正在使用端点 URL 中的用户名与服务交谈? 对不起,我不明白答案。你如何处理有角度的会话? session.user 设置在哪里?你能做一个这样的代码示例吗?谢谢 会话在客户端而不是服务器端处理,客户端保存令牌并将其作为它发出的每个请求的一部分发送。服务器验证令牌并处理请求 了解它的人可以为我们其他人编辑这个答案吗?【参考方案2】:我认为每个 JSON 响应都应该包含一个属性(例如 authenticated: false),并且客户端必须每次都对其进行测试:如果为 false,那么 Angular 控制器/服务将“重定向”到登录页面。
如果用户捕获 de JSON 并将 bool 更改为 True,会发生什么?
我认为你永远不应该依赖客户端来做这些事情。如果用户未通过身份验证,服务器应该只重定向到登录/错误页面。
【讨论】:
检查这个:github.com/witoldsz/angular-http-auth - 拦截器检查服务器响应状态码,如果是 403('需要登录'),它会广播一个事件,所以你可以在应用程序中捕获它并显示登录框。 停止使用答案互相回复。这就是 cmets 的用途! @aherok 建议,您的评论应该被提升为一个答案,它会及时投票到顶部。剩下的只是噪音。【参考方案3】:我在这里回答了类似的问题:AngularJS Authentication + RESTful API
我为UserApp 编写了一个AngularJS module,它支持受保护/公共路由、登录/注销时重新路由、用于状态检查的心跳、将会话令牌存储在cookie、事件等中。
你可以:
-
修改模块并将其附加到您自己的 API,或
将该模块与UserApp(基于云的用户管理API)一起使用
https://github.com/userapp-io/userapp-angular
如果您使用 UserApp,则无需为用户内容编写任何服务器端代码(不仅仅是验证令牌)。带上course on Codecademy 试试看吧。
这里有一些例子说明它是如何工作的:
如何指定哪些路由应该是公开的,哪些路由是登录表单:
$routeProvider.when('/login', templateUrl: 'partials/login.html', public: true, login: true);
$routeProvider.when('/signup', templateUrl: 'partials/signup.html', public: true);
$routeProvider.when('/home', templateUrl: 'partials/home.html');
.otherwise()
路由应设置为您希望用户在登录后重定向到的位置。示例:
$routeProvider.otherwise(redirectTo: '/home');
带有错误处理的登录表单:
<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>
带有错误处理的注册表单:
<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>
退出链接:
<a href="#" ua-logout>Log Out</a>
(结束会话并重定向到登录路径)
访问用户属性:
使用user
服务访问用户属性,例如:user.current.email
或者在模板中:<span> user.email </span>
隐藏仅在登录时才可见的元素:
<div ng-show="user.authorized">Welcome user.first_name !</div>
根据权限显示元素:
<div ua-has-permission="admin">You are an admin</div>
要对您的后端服务进行身份验证,只需使用user.token()
获取会话令牌并将其与 AJAX 请求一起发送。在后端,使用UserApp API(如果您使用UserApp)来检查令牌是否有效。
如果您需要任何帮助,请告诉我!
【讨论】:
我将如何“修改模块并将其附加到您自己的 API” ?【参考方案4】:我创建了一个 github 存储库,基本上总结了这篇文章:https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
ng-login Github repo
Plunker
我会尽量解释清楚,希望对你们中的一些人有所帮助:
(1) app.js:在应用定义中创建身份验证常量
var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
/*Constants regarding user login defined here*/
.constant('USER_ROLES',
all : '*',
admin : 'admin',
editor : 'editor',
guest : 'guest'
).constant('AUTH_EVENTS',
loginSuccess : 'auth-login-success',
loginFailed : 'auth-login-failed',
logoutSuccess : 'auth-logout-success',
sessionTimeout : 'auth-session-timeout',
notAuthenticated : 'auth-not-authenticated',
notAuthorized : 'auth-not-authorized'
)
(2) Auth Service: 以下所有功能均在 auth.js 服务中实现。 $http 服务用于与服务器通信以进行身份验证过程。还包含授权功能,即是否允许用户执行特定操作。
angular.module('loginApp')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS',
function($http, $rootScope, $window, Session, AUTH_EVENTS)
authService.login() = [...]
authService.isAuthenticated() = [...]
authService.isAuthorized() = [...]
authService.logout() = [...]
return authService;
]);
(3) 会话: 保存用户数据的单例。这里的实现取决于你。
angular.module('loginApp').service('Session', function($rootScope, USER_ROLES)
this.create = function(user)
this.user = user;
this.userRole = user.userRole;
;
this.destroy = function()
this.user = null;
this.userRole = null;
;
return this;
);
(4) 父控制器: 将其视为应用程序的“主要”功能,所有控制器都继承自此控制器,它是此应用程序身份验证的支柱。
<body ng-controller="ParentController">
[...]
</body>
(5) 访问控制:要拒绝某些路线的访问,必须执行 2 个步骤:
a) 在 ui 路由器的 $stateProvider 服务上添加允许访问每个路由的角色数据,如下所示(同样适用于 ngRoute)。
.config(function ($stateProvider, USER_ROLES)
$stateProvider.state('dashboard',
url: '/dashboard',
templateUrl: 'dashboard/index.html',
data:
authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
);
)
b) 在 $rootScope.$on('$stateChangeStart') 上添加功能以防止用户未授权时更改状态。
$rootScope.$on('$stateChangeStart', function (event, next)
var authorizedRoles = next.data.authorizedRoles;
if (!Auth.isAuthorized(authorizedRoles))
event.preventDefault();
if (Auth.isAuthenticated())
// user is not allowed
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
else
// user is not logged in
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
);
(6) Auth拦截器:这个是实现的,但是不能对这段代码的范围进行检查。在每个 $http 请求之后,此拦截器都会检查状态码,如果返回以下之一,则它会广播一个事件以强制用户重新登录。
angular.module('loginApp')
.factory('AuthInterceptor', [ '$rootScope', '$q', 'Session', 'AUTH_EVENTS',
function($rootScope, $q, Session, AUTH_EVENTS)
return
responseError : function(response)
$rootScope.$broadcast(
401 : AUTH_EVENTS.notAuthenticated,
403 : AUTH_EVENTS.notAuthorized,
419 : AUTH_EVENTS.sessionTimeout,
440 : AUTH_EVENTS.sessionTimeout
[response.status], response);
return $q.reject(response);
;
]);
P.S. 通过添加包含在directives.js 中的指令,可以轻松避免第一篇文章中所述的表单数据自动填充错误。
P.S.2 用户可以轻松调整此代码,以允许看到不同的路线,或显示不应该显示的内容。逻辑必须在服务器端实现,这只是在您的 ng-app 上正确显示内容的一种方式。
【讨论】:
我一直在按照您的指南来了解客户端逻辑。真的很棒!!我错过了一些关于手动销毁会话的内容,但我们也必须进行试验和破坏! ~~不确定我是否正确理解该行:authService.login() = [...]
那些方括号将代表类似$http.get(url, uID, pwd
?~~ 好的,看看 plunker,就像我说的那样 XD
你能扩展你的服务器端答案吗?【参考方案5】:
在 angularjs 中,您可以创建 UI 部分、服务、指令以及 angularjs 中代表 UI 的所有部分。这是一项不错的技术。
作为任何刚接触这项技术并想要验证“用户”身份的人,我建议使用 c# web api 的强大功能。为此,您可以使用 OAuth 规范,该规范将帮助您建立强大的安全机制来验证用户身份。使用 OAuth 构建 WebApi 后,您需要调用该 api 以获得令牌:
var _login = function (loginData)
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'token', data, headers: 'Content-Type': 'application/x-www-form-urlencoded' ).success(function (response)
localStorageService.set('authorizationData', token: response.access_token, userName: loginData.userName );
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
deferred.resolve(response);
).error(function (err, status)
_logOut();
deferred.reject(err);
);
return deferred.promise;
;
一旦获得令牌,您就可以在 Token 的帮助下从 angularjs 请求资源,并使用 OAuth 规范访问在 Web Api 中保持安全的资源。
请查看以下文章以获得更多帮助:-
http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/
【讨论】:
【参考方案6】:var _login = function (loginData)
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'token', data, headers: 'Content-Type': 'application/x-www-form-urlencoded' ).success(function (response)
localStorageService.set('authorizationData', token: response.access_token, userName: loginData.userName );
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
deferred.resolve(response);
).error(function (err, status)
_logOut();
deferred.reject(err);
);
return deferred.promise;
;
【讨论】:
以上是关于AngularJS:在单页应用程序中使用身份验证的基本示例的主要内容,如果未能解决你的问题,请参考以下文章