JWT如何退出

时间:2016-09-06 15:36:10

标签: ruby-on-rails devise jwt

  • Ruby 2.2.4
  • Rails 4.1.8
  • Devise 3.4.1

大家好, 我接受了一个教程(https://github.com/jimjeffers/rails-devise-cors-jwt-example),当通过JSON远程进行身份验证时,它会覆盖Devise传递JWT。但是我想通过注销功能改进这个应用程序。但是我该怎么做?实际上,使用本教程中的代码,一旦我成功通过身份验证,我就无法注销或再次注册:

 You are already signed in.

    Welcome#index

    Find me in app/views/welcome/index.html.erb

问题是,我该怎么做?我该如何实施,用户可以注销或重新注册?

以下是代码的一部分: 的 registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  # Disable CSRF protection
  skip_before_action :verify_authenticity_token

  # Be sure to enable JSON.
  respond_to :html, :json
end

session_controller.rb

# This is an example of how to extend the devise sessions controller
# to support JSON based authentication and issuing a JWT.
class Users::SessionsController < Devise::SessionsController
  # Require our abstraction for encoding/deconding JWT.
  require 'auth_token'


  # Disable CSRF protection
  skip_before_action :verify_authenticity_token

  # Be sure to enable JSON.
  respond_to :html, :json

  # POST /resource/sign_in
  def create

    # This is the default behavior from devise - view the sessions controller source:
    # https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L16
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_flashing_format?
    sign_in(resource_name, resource)
    yield resource if block_given?

    # Here we're deviating from the standard behavior by issuing our JWT
    # to any JS based client.
    token = AuthToken.issue_token({ user_id: resource.id })
    respond_to do |format|
      format.json { render json: {user: resource.email, token: token} }
    end

    # The default behavior would have been to simply fire respond_with:
    # respond_with resource, location: after_sign_in_path_for(resource)
  end
end

api_controller.rb

class ApiController < ApplicationController
  # No action on this controller is accessible without a
  # supplying a valid token.
  before_filter :verify_jwt_token

  def test
    respond_to do |format|
      format.json { render json: {'sample' => 'data'}}
    end
  end
end

application_controller.rb

class ApplicationController < ActionController::Base
  # We depend on our auth_token module here.
  require 'auth_token'
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  # protect_from_forgery with: :null_session
  protected
    ##
    # This method can be used as a before filter to protect
    # any actions by ensuring the request is transmitting a
    # valid JWT.
    def verify_jwt_token
      head :unauthorized if request.headers['Authorization'].nil? ||
          !AuthToken.valid?(request.headers['Authorization'].split(' ').last)
    end
end

模型/ user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

的routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations'
  }
  get '/api/test', to: 'api#test'
  root 'welcome#index'
end

LIB / auth_token.rb

require 'jwt'

module AuthToken
  def AuthToken.issue_token(payload)
    payload['exp'] = 24.hours.from_now.to_i # Set expiration to 24 hours.
    JWT.encode(payload, Rails.application.secrets.secret_key_base)
  end

  def AuthToken.valid?(token)
    begin
      JWT.decode(token, Rails.application.secrets.secret_key_base)
    rescue
      false
    end
  end
end

任何想法或建议都会对我有所帮助。多年来我一直在努力解决这个问题

更新:这是我的Android界面界面,如何实现删除功能?

public interface Interface {

    //This method is used for "POST"
    @FormUrlEncoded

    @POST("/")
    void postData(@Field("method") String method,
                  @Field("email") String username,
                  @Field("password") String password,
                  Callback<ServerResponse> serverResponseCallback);
}

2 个答案:

答案 0 :(得分:3)

正如Florent所说,在客户端上你只需要删除令牌(从你的SharedPreferences或你用来存储当前令牌的任何其他持久存储中删除它),对于服务器端你有几个选项,如下所示:最好还是好的。

刷新令牌:最佳选择,您可以阅读here。基本上,您有两种令牌,一种访问权限和一种刷新令牌。刷新令牌用于在访问令牌过期后续订。例如,在您目前的24小时方法中,用户需要每天登录。但是,如果您注销,则会删除客户端中的两个令牌,并且访问令牌最终会过期。

重新发行代币:它是前一个更简单,更天真的版本。添加重发令牌功能,让您更新当前令牌(再次在您的代码中调用AuthToken.issue_token)。您的客户可以在当前令牌到期之前的某个时间调用它。

黑名单令牌:在这种情况下,您需要将以前使用过的令牌存储在数据库中,这种做法会失败,因为您必须不断对数据库进行验证而不是仅仅解码。

答案 1 :(得分:0)

除非您将撤销的令牌列入黑名单(这意味着您将失去JWT提供的所有好处),否则您无法使用JWT注销。 我建议您设置较低的令牌生存期(例如5分钟而不是24小时),如果需要,可以通过刷新令牌(生命周期可能是24小时)续订令牌。