构建一个双头身份验证怪物
所以你描述的是可能的,但肯定会很痛苦。您将不得不构建一堆代码来确定用户是否是 Rails 端的 NormalUser 和 AdminUser。在 Angular 方面,您必须确定用户需要哪个登录名,NormalUser 与 AdminUser。话虽如此,这是可能的,这里有一些应该有所帮助的指针。
文档是你的朋友
You really really really want to have a good understanding of how Devise works.Devise 在幕后做了很多魔术。
要使用Angular 进行身份验证,您需要熟悉$httpProvider.interceptors、Services 和Resources。
导轨
路线
在 Devise 中有两个模型的示例路线:
devise_for :normal_users
devise_for :admin_users
# route for the sample controller below
resource :users do
collection do
get :current
end
end
Devise 带来了什么
Devise 将在您的控制器中按照以下方式创建 helper methods:
current_normal_user
authenticate_normal_user!
current_admin_user
authenticate_admin_user!
因此,您必须检查两者以查看会话是否已通过身份验证,最好的计划是将两个检查包装到自定义 before_action 中,类似于 before_action :authenticate_all_users。
用户控制器示例
这是一个示例 UsersControllers,它返回 JSON Angular 将用于检查身份验证。
class UsersController < ApplicationController
# Needs a before_action that authenticates the user
respond_to :json
def current
@user = current_normal_user || current_admin_user
respond_with @user
end
end
角度
安全网
我发现这个拦截器在 Angular 中处理身份验证时非常有用。在设置 Angular 时将此添加到您的 app.config,如果任何 http 请求返回 401 状态代码,它将重定向到指定页面。这比强制所有资源处理用户未通过身份验证的可能性要简单。 (作为咖啡师)
# Monitors the requests and responses of angular
# * Redirects to /users/sign_in if status is a 401
app.config [
"$httpProvider"
($httpProvider) ->
$httpProvider.interceptors.push ($q) ->
request: (config) ->
config or $q.when(config)
requestError: (rejection) ->
$q.reject rejection
response: (response) ->
response or $q.when(response)
responseError: (rejection) ->
# Not logged in, redirect to login
if rejection.status is 401
$q.reject rejection
# Change this with desired page
window.location = "/users/sign_in"
else
$q.reject rejection
在您的场景中,您可能需要添加逻辑来确定他们应该看到哪个登录页面,normal_user 与 admin_user。
用户信息
最后是一个获取用户信息的示例 Angular 服务。如果用户没有被认证,401状态会被之前的$httpProvider捕捉到,对用户进行相应的处理。否则,如果用户通过身份验证,用户的信息将填充到$rootScope.currentUser。您只需将其作为依赖项添加到应受身份验证保护的控制器中。 (在咖啡脚本中)
angular.module("TheAngularApp.services").service "CurrentUserService", ($rootScope, $http, CurrentUser, User) ->
userService =
reloadCurrentUser: ->
@currentUser = CurrentUser.show((user) ->
# set in scope
$rootScope.currentUser = user
)
@currentUser
userService.reloadCurrentUser()
userService
此服务依赖于指向 /users/current.json 端点的 CurrentUser 资源。在您使用 CurrentUserService 的场景中,处理多个模型的可能选项是:
- 检查两次用户是否已通过身份验证,一次用于 normal_user,一次用于 admin_user
- 创建一个自定义控制器方法来检查 normal_user 和 admin_user 的身份验证,这大致就是示例 rails 控制器正在做的事情。
额外积分
或者,我会研究 ng-idle 作为允许会话在 Angular 中过期的一种方式。
评论更新
我的登录页面在用户信息的后端请求发生时开始显示,因此重定向到登录页面非常明显并导致用户体验不佳。
最简单的方法是使用非角度页面进行登录,例如 Devise 提供的页面。一旦用户成功登录,他们被定向到的页面就会加载 Angular 应用程序。这样,您始终可以假设用户在使用 Angular 时已登录。
如果这不可能,您将不得不从 Angular 发出身份验证请求。这意味着您需要让用户等待,直到您可以从身份验证请求中检查承诺。一旦它有效,您将用户移动到正确的路线。
警告 我相信如果您登录失败,Devise 会发送一个状态码 401,这将使前面讨论的拦截器跳闸。为了解决这个问题,拦截器必须排除处理身份验证请求的路径。
处理身份验证的示例资源:
Session.create {email: email, password: password}, success = (user) ->
# User was successfully authenticated
$scope.currentUser = user
$location.path( "/" );
, error = (data, status, headers, config) ->
# Failed to auth, notify user
)