建造一个两头的 Auth 怪物
所以你所描述的情况是可能的,但肯定会很痛苦。您必须构建一堆代码来确定用户是 Rails 端的 NormalUser 还是 AdminUser。在 Angular 方面,您必须确定用户需要哪种登录,NormalUser 与 AdminUser。话虽这么说,这是可能的,这里有一些应该有所帮助的建议。
文档是你的朋友
您真的非常非常想很好地了解 Devise 的工作原理。Devise 在幕后发挥了很多魔力。
对于授权使用Angular,你需要熟悉$httpProvider.拦截器, Services, and 资源.
Rails
Routes
在 Devise 中拥有两个模型的示例路线:
devise_for :normal_users
devise_for :admin_users
# route for the sample controller below
resource :users do
collection do
get :current
end
end
设备带来了什么
设计将创造辅助方法在你的控制器中沿着以下路线:
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
设置 Angular 时,如果任何 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
该服务取决于CurrentUser
指向的资源/users/current.json
端点。在使用 CurrentUserService 的场景中,处理多个模型的可能选项有:
- 检查两次用户是否已通过身份验证,一次检查 normal_user,另一次检查 admin_user
- 创建一个自定义控制器方法来检查normal_user和admin_user的身份验证,这大致就是示例rails控制器正在做的事情。
额外学分
或者,我会调查ng-idle作为允许会话在 Angular 中过期的一种方式。
评论更新
当后端请求用户信息时,我的登录页面开始显示,因此登录页面的重定向非常明显,并导致糟糕的用户体验。
最简单的方法是使用非角度页面进行登录,例如 Devise 提供的页面。用户成功登录后,他们被定向到的页面将加载 Angular 应用程序。这样,您始终可以假设用户在使用 Angular 时已登录。
如果这不可能,您将必须从 Angular 发出身份验证请求。这意味着您需要让用户等待,直到您可以检查身份验证请求中的承诺。一旦有效,您就可以将用户移动到正确的路线。
WARNING我相信如果您登录失败,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
)