Devise,devise_token_auth和ng-token-auth的身份验证问题 [英] Authentication issue with Devise, devise_token_auth, and ng-token-auth

查看:83
本文介绍了Devise,devise_token_auth和ng-token-auth的身份验证问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点卡住了,但我找不到解决方法.我有一个Rails网站,将devise用于前端,将devise_token_auth用于api.前端结合使用服务器端呈现的页面和api调用来向用户显示数据. 如果我使用纯角度登录,则登录表单最终将起作用(通常需要提交2-3个):

Im a little stuck and i haven't been able to find a solution. I have a rails site that uses devise for the front end and devise_token_auth for the api. The front end uses a combination of server sided rendered pages and api calls to to display data to the user. The login form will eventally work (ushally 2-3 submits) if i use a pure angular login:

%div{'ng-controller'=>'logInCtrl'}
  %h2 Log In
  %div{:layout=>'column'}
    %div{:flex=>20}
    %div{:flex=>60, :layout=>'column'}
      = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
        %div{:layout=>'column'}
          %md-input-container
            =f.label :login
            %input{'ng-model'=>'loginForm.login', :autofocus => 'true'}
          %md-input-container
            = f.label :password
            %input{:type=>'password', 'ng-model'=>'loginForm.password', :autocomplete => 'off'}

          %md-input-container
            %md-button.md-raised.md-primary{'ng-click'=>'submitMe()'}
              -#{:type=>'submit'}
              %md-icon.mdi.mdi-account-key
              Log In

:coffee
  myApp.controller 'logInCtrl', ($scope, $resource, $http, $mdDialog, $auth ) ->
    $scope.submitMe = () ->
      $auth.submitLogin($scope.loginForm).then( (resp)->
        location.replace('/users/sign_in')
      )

如果我使用标准的发布方法,则服务器将提供正确的信息,但没有为ng-token-auth设置令牌.我可以使用以下方法在session#create上手动生成和发送令牌标头:

If i use a standard post method the correct information is rendered by the server but there is not token set for ng-token-auth. I can generate and send the token headers manually on session#create using:

  # POST /resource/sign_in
  def create
    super do |user|
      newAuth = user.create_new_auth_token
      response.headers.merge!(newAuth)
    end
  end

这种方法的问题在于ng-token-auth从未从标头中提取令牌,因为它没有发出请求.我一直在寻找一种手动设置令牌标头的方法,但是没有运气.

The issue that i have with this approach is that ng-token-auth never picks up the token from the headers since it didn't make the request. I've looked for a way to manual set the token header with no luck.

-顺便说一句,我最终不会转向oauth解决方案,因此我使用的任何解决方法都需要移植到该解决方案. -我应该提到服务器端渲染要照顾到设计元素以及打开和关闭功能.我还使用current_user的元素根据用户位置设置表名称的子集.

-- As a side not i will eventually be moving to a oauth solution so whatever workaround i use will need to port to that. -- I should mention that the server side rendering take care of design elements as well as turning function on and off. I also use an element of current_user to set a sub-set of table names based on a users location.

推荐答案

经过一番研究和一些时间,我想出了一个可行的解决方案,尽管有点棘手.

After some research and a little time I came up with a solution that works, although a little hacky.

Devise创建新会话时,将重定向到配置文件中指定的路由,因此设置所有变量都将丢失.第二个问题是ng-token-auth将仅设置和使用在登录功能期间设置的令牌,因此无法检测到仅通过页面标头发送令牌(这是浏览器的限制,而不是代码的限制).

When Devise creates a new session a redirect is called to the route specified in your configuration files, so setting any variables is lost. the second issue is that ng-token-auth will only set and use a token that is set during the sign-in function, so simply sending a token via the pages headers is not detected (this is a limitation of the browser not the code).

尝试使用ng-token-auth进行不同的迭代并为用户进行标准的devise身份验证后,我得出的结论是,最好先通过devise授权用户,然后以某种方式用ng-token-auth设置令牌;因此,我开始研究ng-token-auth在它通过登录收到令牌时的实际操作.事实证明,它设置了两个cookie:

After trying different iterations of using ng-token-auth and a standard devise authentication for my user I came to the conclusion that it would better to first authorize the user with devise and then somehow set a token with ng-token-auth; so I started to research what ng-token-auth actually did when it received a token via login. It turns out that it sets two cookies:

currentConfigName |默认值 |/| 到期日期

currentConfigName | default | domain | / | exp date

auth_headers | URL编码的令牌数据 | |/| 到期日期

auth_headers | url encoded token data | domain | / | exp date

现在的问题是如何将新生成的令牌传递到前端;这使我们比我想象的要简单.因为在Rails的调用之间唯一保留的数据是会话数据,所以我决定在会话数据中添加一个标志是有意义的,这标志着我的ApplicationController生成了一个新密钥.

Now the issue was how to pass a newly generated token to the front end; this turned our to be simpler than I thought. Since the only data that is persisted between calls in Rails is session data I decided it would make sense to add a flag to the session data which signaled my ApplicationController to generate a new key.

首先我扩展了Devise::SessionsController#create

def create
  super do |user|
    session[:token] = true
  end
end

这会将名为token的会话变量设置为True.比在ApplicationController中我添加的内容:

This sets a session variable named token to True. Than in ApplicationController I added:

 before_filter :set_token

  def set_token
    if session[:token] && user_signed_in?
      newAuth = current_user.create_new_auth_token
      response.headers.merge!(newAuth)
      @auth_token = newAuth
      session.delete(:token)
    else
      @auth_token = false
    end
  end

此前过滤器将查找session[:token],如果设置调用devise-token-authcreate_new_auth_token函数以登录"当前用户.此标头信息既被写入传出页标头,也被分配给变量@auth_token. 最后,在 views/laoyouts/applicationhtml.haml 中,此代码块被添加到%body标记之后

This before filter looks for session[:token] and if set calls devise-token-auth's create_new_auth_token function to 'sign-in' the current user. This header information is both written to the outgoing pages headers as well as assigned to the variable @auth_token. Finally in views/laoyouts/applicationhtml.haml this code block is added to right after the %body tag

- if @auth_token
  :coffee
    myApp.controller 'cookieController', ($scope, $resource, $http, $mdDialog, $auth, ipCookie ) ->
      ipCookie('auth_headers', "{\"access-token\": \"#{@auth_token['access-token']}\",\"token-type\": \"Bearer\",\"client\": \"#{@auth_token['client']}\",\"expiry\": \"#{@auth_token['expiry']}\",\"uid\": \"#{@auth_token['uid']}\"}", {path: "/",expires: 9999,expirationUnit: 'days',secure: false})
      ipCookie('currentConfigName', 'default', {path: "/",expires: 9999,expirationUnit: 'days',secure: false})
  %div{'ng-controller'=>'cookieController'}

这将添加一个空的div标签和角度控制器,该控制器使用写入@auth_token的数据和ipCookie函数(ng-token-auth要求)来写入必要的cookie.

This adds an empty div tag and angular controller that uses the data written to @auth_token and the ipCookie function (required by ng-token-auth) to write the necessary cookies.

一些注意事项:

  • 我在主布局页面和ApplicationController中添加了代码块,因为当用户登录到我的网站时,根据其凭据,他们可能会重定向到两个页面之一.这样可以确保无论将它们发送到代码令牌的页面是什么,都将生成并插入代码块.
  • 我知道,可能有一种更好的方法来处理cookie的生成,而不是创建一个空的div并为其分配控制器.我愿意接受更优雅的解决方案.
  • I added the code block to the main layout page and ApplicationController because when a user is signed into my site they may be redirected to one of two pages depending on their credentials. This ensures that no matter what page they are sent to the code token is generated and the code block is inserted.
  • I know that there is probably a better way to handle the generation of the cookies instead of creating an empty div and assigning a controller to it. I am open to more elegant solutions.

这篇关于Devise,devise_token_auth和ng-token-auth的身份验证问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆