【问题标题】:Simple Auth Devise giving unauthenticated error in Ember Rails简单的身份验证设计在 Ember Rails 中给出未经身份验证的错误
【发布时间】:2015-02-18 01:50:26
【问题描述】:

我正在设置一个由 ruby​​ on rails 支持的 ember 应用程序。我在使用 simple-auth 和 simple-auth-devise 登录时遇到了问题。当我提交正确的用户名和密码时,我成功检索了会话身份验证令牌和用户名,但我仍然收到 401 拒绝访问错误,我不知道为什么。我怀疑这可能与电子邮件与 user_email 和令牌与 user_token 业务的命名有关。我主要从dayjot 获取这段代码,所以你会认为追踪这个错误很简单,但我在找到确切问题时遇到了很多问题。感谢您能给我的任何帮助!

我在 rails 服务器中得到的确切错误是:

Started GET "/users/me" for 127.0.0.1 at 2015-02-17 10:25:31 -0600
Processing by UsersController#me as JSON
  Parameters: {"user"=>{}}
Filter chain halted as :authenticate_user! rendered or redirected
Completed 401 Unauthorized in 5ms (Views: 4.1ms | ActiveRecord: 0.0ms)
In rails, this is my application controller:

这是我的应用程序控制器:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  # protect_from_forgery with: :null_session

  before_action :authenticate_user_from_token!, :handle_html
  around_action :user_time_zone, if: :current_user

  def index
    render file: 'public/index.html'
  end

  protected

  def authenticate_user!
    render(json: {}, status: 401) unless current_user
  end

  private

  def authenticate_user_from_token!
    authenticate_with_http_token do |token, options|
      user_email = options[:user_email].presence
      user       = user_email && User.find_by_email(user_email)

      if user && Devise.secure_compare(user.authentication_token, token)
        request.env['devise.skip_trackable'] = true
        sign_in user, store: false
      end
    end
  end

  def user_time_zone(&block)
    Time.use_zone(current_user.time_zone, &block)
  end

  # If this is a get request for HTML, just render the ember app.
  def handle_html
    render 'public/index.html' if request.method == 'GET' && request.headers['Accept'].match(/html/)
  end
end

我的会话控制器如下所示:

class SessionsController < Devise::SessionsController
  def create
    self.resource = warden.authenticate!(auth_options)
    sign_in(resource_name, resource)
    data = {
      user_token: self.resource.authentication_token,
      user_email: self.resource.email
    }
    render json: data, status: 201
  end

  def destroy
    sign_out :user
    render json: {}, status: :accepted
  end
end

我的序列化器是这些:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :password, :user_email, :email, :user_token, :passwordConfirmation
end

class UserSerializer < ActiveModel::Serializer
  attributes :id, :email, :email_times, :last_export_time, :plan, 
             :plan_started, :plan_canceled, :plan_status, :trial_end, 
             :time_zone, :status, :created_at, :include_email_memory
end

我的路线是:

Rails.application.routes.draw 做

  # PLANS
  post 'update_plan' => 'plans#update_plan', as: :update_plan
  post 'update_card' => 'plans#update_card', as: :update_card
  post 'cancel_plan' => 'plans#cancel_plan', as: :cancel_plan

  # PASSWORDS
  post 'start_password_reset' => 'users#start_password_reset'
  put  'finish_password_reset' => 'users#finish_password_reset'
  get  'password-reset' => 'application#index', as: :edit_user_password

  # USERS
  devise_for :users, controllers: { sessions: 'sessions' }, :skip => [:passwords]
  resources :users, only: [:create, :update] do 
    get 'me' => 'users#me', on: :collection
  end

  # background processing admin
  match "/delayed_job" => DelayedJobWeb, :anchor => false, via: [:get, :post]    

  # catch-all for ember app
  get '*path' => 'application#index', :constraints => { :format => 'html' }


end

在 ember-cli 应用程序本身中,我的登录控制器是:

import Ember from "ember";

export default Ember.Controller.extend({
  authenticator: 'simple-auth-authenticator:devise',

  identification: null,
  password: null,
  error: null,
  working: false,

  actions: {
    authenticate: function() {
      var _this = this,
          data = this.getProperties('identification', 'password');

      this.setProperties({
        working: true,
        password: null,
        error: null
      });

      this.get('session').authenticate('simple-auth-authenticator:devise', data).then(function() {
        // authentication was successful
      }, function(data) {
        _this.set('working', false);
        _this.set('error', data.error);
      });
    }
  }
});

我的申请途径是:

// ember-simple-auth
import Ember from "ember";
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
import Notify from 'ember-notify';
import ENV from 'front-end/config/environment';

export default Ember.Route.extend(ApplicationRouteMixin, {
  beforeModel: function(transition) {
    this._super(transition);    
    return this.setCurrentUser();
  },
  actions: {
    sessionAuthenticationFailed: function(data) {
      this.controllerFor('login').set('working', false);
      this.controllerFor('login').set('loginErrorMessage', data.message);
    },
    sessionInvalidationSucceeded: function() {
      this.transitionTo('index');
    },
    sessionAuthenticationSucceeded: function() {
      var _this = this;
      this.controllerFor('login').set('working', false);

      this.setCurrentUser().then(function() {
        if (_this.get('session.currentUser.mustSubscribe')) {
          _this.transitionTo('plans');
        } else {
          _this.transitionTo('courses');
        }
      });      
    },
    authorizationFailed: function() {
      Notify.error("Could not be authenticated.. signing out.", {closeAfter: 5000});
      this.get('session').invalidate();
    }
  },

  setCurrentUser: function() {

    var _this = this,
        adapter = this.get('store').adapterFor('user');

    if (this.get('session.isAuthenticated')) {
      return new Ember.RSVP.Promise(function(resolve) {
        adapter.ajax(ENV.APP.API_HOST + "/users/me", "GET", {}).then(
          function(response){
            _this.store.pushPayload(response);
            var user = _this.store.find('user', response.user.id);
            resolve(user);
          },
          function(response){
            resolve(response);
          }
        );
      }).then(function(user) {
        _this.set('session.currentUser', user);  
      }, function() {
        Notify.error("Could not be authenticated.. signing out.", {closeAfter: 5000});
        _this.get('session').invalidate();
      });
    } else {
      return new Ember.RSVP.Promise(function(resolve){ resolve(); });
    }
  }
});

最后我的登录路径是:

import Ember from "ember";

export default Ember.Route.extend({
  activate: function() {
    if (this.get('session').isAuthenticated) {
      this.transitionTo('courses');
    }
  }
});

模板是:

<form {{action 'register' on='submit'}} class='d-auth-form fade-in'>

  {{#each errors}}
    <div class="d-error">
      {{this}}
    </div>
  {{/each}}

  {{input placeholder='Email' type='email' value=email autocomplete='off' autocapitalize="none"}}
  {{input placeholder='Password' type='password' value=password autocomplete='off'}}
  <button type="submit" class='d-btn d-btn--success' {{bind-attr disabled=working}}>
    {{#if working}}
      Registering..
    {{else}}
      Sign up for DayJot for free
    {{/if}}
  </button>

  <ul class='d-links'>
    <li>{{#link-to 'login'}}Login to existing account{{/link-to}}</li>
  </ul>
</form>

environment.js 的重要部分是:

    'simple-auth': {
      crossOriginWhitelist: ['http://localhost:3000','http://localhost:4202','https://api.dayjot.com'],
      authorizer: 'simple-auth-authorizer:devise',
      authenticationRoute: 'index'
    } 

  ENV['simple-auth-devise'] = {
    serverTokenEndpoint: ENV.APP.API_HOST+'/users/sign_in',
    identificationAttributeName: 'email'

  }

【问题讨论】:

  • 我阅读了自述文件,并大大简化了 Ember 应用程序和登录路由以及控制器,使其成为自述文件中推荐的内容。它现在登录了,这很棒,但是页面会自行刷新并且页面不再登录。是什么导致了这些硬刷新,有没有办法修复它?另外,我认为即使该人在浏览器中进行了硬刷新,我也想存储令牌,这样他们就不必登录。有没有办法存储它?我启用了 Crsf 令牌,这似乎很好。

标签: ruby-on-rails ember.js devise


【解决方案1】:

结帐the README - Ember Simple Auth Devise 期望令牌返回为token,但是您使用的是user_token。因此,会话实际上永远不会在 Ember 中进行身份验证,并且令牌不会包含在导致 401 响应的请求中。

【讨论】:

  • 感谢您的回复,但是当我更改会话控制器时,这似乎没有任何改变。我仍然收到 401 错误
  • 您能否在身份验证后检查会话的内容(直接在 localStorage 中或通过 Ember Inspector 的容器视图)?另外,失败的请求是否包含Authorization 标头?
  • 现在看来可以登录了,在本地存储为key:ember_simple_auth:session,value:{"authenticator":"simple-auth-authenticator:devise","令牌":"at63qvxugbol0p35fdctr2","user_email":"ars@ars.com"}。刷新页面会立即让我退出。 (有时基于所使用的浏览器,它会在登录后立即刷新,这也会立即让我退出。)有没有更好的方法来更永久地存储会话?再次感谢!
  • 您将identificationAttributeName 配置为'email' 但您的服务器返回user_email 这您的会话未被识别为实际完成。你必须改变任何一方来匹配另一方。
猜你喜欢
  • 2020-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多