2017-03-01 34 views
0

Im有點卡住了,我一直無法找到解決方案。我有一個rails站點,它使用devise作爲前端,devise_token_auth作爲api。前端使用服務器端渲染頁面和API調用的組合來向用戶顯示數據。 登錄表單將eventally工作(ushally 2-3的提交)如果我使用純角登錄:Devise,devise_token_auth和ng-token-auth身份驗證問題

%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。我可以手動生成和發送令牌頭會話#創建使用:

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

,我有這種方法的問題是,NG-令牌身份驗證從未拿起從因爲它沒有頭的令牌提出請求。我已經尋找了一種手動設置令牌頭的方法,但沒有運氣。

- 作爲一方,我不會最終轉向oauth解決方案,所以無論我使用哪種解決方法都需要移植到該解決方案。 - 我應該提到服務器端渲染負責設計元素以及打開和關閉功能。我還使用current_user的一個元素根據用戶位置設置表名的子集。

回答

0

經過一番研究和一段時間後,我想出了一個可行的解決方案,雖然有點冒險。

當Devise創建一個新的會話時,重定向被調用到配置文件中指定的路由,所以設置任何變量都會丟失。第二個問題是,ng-token-auth只會設置並使用在登錄功能期間設置的令牌,因此僅通過頁眉發送令牌不會被檢測到(這是瀏覽器的限制而不是代碼)。

在嘗試了使用ng-token-auth和我的用戶的標準設計認證的不同迭代之後,我得出結論:最好先用devise授權用戶,然後以ng-token-auth設置令牌;所以我開始研究ng-token-auth在通過登錄接收到令牌時實際做了什麼。事實證明,它設置了兩個餅乾:

currentConfigName |默認| 域名 |/| exp date

auth_headers | url編碼的令牌數據 | 域名 |/| exp date

現在的問題是如何將新生成的令牌傳遞給前端;這使我們變得比我想象的更簡單。由於在Rails中調用的唯一數據是會話數據,因此我決定向會話數據添加一個標誌,這標誌着我的ApplicationController生成一個新的密鑰。

首先我伸出Devise::SessionsController#create

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

這臺命名爲tokenTrue一個會話變量。比ApplicationController我說:

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。 最後在視圖/ laoyouts/applicationhtml.haml這個代碼塊的%body標籤

- 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)來編寫必要的cookies。

幾點注意事項:

  • 我添加的代碼塊主要佈局頁和ApplicationController因爲當用戶登錄到我的網站,他們可以根據自己的憑據被重定向到兩個中的一個頁面。這確保了無論他們發送到代碼令牌的頁面被生成並且代碼塊被插入。
  • 我知道可能有更好的方法來處理cookie的生成,而不是創建一個空的div併爲其分配一個控制器。我願意接受更優雅的解決方案。