Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
216 views
in Technique[技术] by (71.8m points)

android - Rails api and native mobile app authentication

I know there is a lot of information about this topic, but I can't find any that is up to date. I see topics like this one relating to rails and android authentication but I see that TokenAuthenticatable is now removed from devise.

My question is simple: is there a good way to authenticate users from native Android and iPhone apps using Rails 4? Does anyone know of good tutorials or articles that provide a solution ?

Adam Waite Adding a bounty:

I have just opened a 500 bounty on this question because I can't find the correct practice for authenticating a user from an iOS app to a Rails API anywhere. This is what I was considering doing but have no idea if it's secure or not?!:

Let's assume we have a User record. A user has signed up for an account which has created a User record in the database with an email column and a password_digest column.

When the user signs-in I would like that user to remain authenticated on the mobile app until explicitly signing-out.

I imagine we're going to need a token based authentication. I would perhaps create an ApiKey record when the User is created and have that saved as an association on the User record.

When the user signs in/up, the response will contain an API token (something like SecureRandom.hex) which will be saved in the iOS Keychain and used with all subsequent requests to verify the user by passing it in a header and verifying it using something like:

before_filter :restrict_access

private

def restrict_access
authenticate_or_request_with_http_token do |token, options|
  ApiKey.exists?(access_token: token)
end

Is this secure? Should I be refreshing the token with every request and including it in the response?

What other options do I have? What do the likes of Facebook, Twitter and Pinterest do?

I am aware of OAuth2.0, but is that not for granting external applications?

Is there a gem that manages any of this?

Sorry, completely unsure here.

500 to the best answer.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Gist of a solution from my research. Feel free to edit, correct, invalidate, etc.

SessionsController < ApplicationController
  skip_before_filter :authenticate_user, :only => [:create]
  def create
    user = User.where("username = ? OR email = ?", params[:username_or_email], params[:username_or_email]).first
    if user && user.authenticate(params[:password])
      api_key = user.find_api_key
      if !api_key.secret_key || api_key.is_expired?
        api_key.set_expiry_date
        api_key.generate_secret_key
      end
      api_key.save
      render json: api_key, status: 201     
    else
      status: 401
    end
  end

Note the ApiAuth.authentic? method and the request object. The request must be signed with an HMAC algorithm on the client.

ApplicationController < ActionController::Base
  respond_to :json
  force_ssl
  protect_from_forgery with: :null_session 
  before_filter :authenticate_user
  private
  def authenticate_user
    if authenticate_user_from_secret_key
      return true
    else
      head :unauthorized 
    end
  end
  def authenticate_user_from_secret_key
    userid = ApiAuth.access_id(request)
    currentuser = userid && User.find_by_id(userid)
    if ApiAuth.authentic?(request, currentuser.find_api_key.secret_key)
      return true
    else
      return false
    end
    false
  end

User creation/registration

UsersController < ApplicationController
  skip_before_filter :authenticate_user, :only => [:create]
  def create
      user = User.create(user_params)
      if !user.new_record?
        render json: user.find_apit_key, status: 201

      else
       # error
      end
  end

Api key model. Similar to api key model in #352 railscast only difference is ApiAuth key generation.

class ApiKey < ActiveRecord::Base
  before_create :generate_secret_key, :set_expiry_date
  belongs_to :user   
  def generate_secret_key
    begin
    self.secret_key = ApiAuth.generate_secret_key
    end while self.class.exists?(secret_key: secret_key)
  end

User model.

class User < ActiveRecord::Base
  has_secure_password
  before_save :ensure_api_key 
  has_many :api_keys 
  def find_api_key
   self.api_keys.active.ios.first_or_create
  end

On the client side the HMAC algorithm must be used to sign requests.

The code is from: [SHA1 HMAC Key generation/authentication] https://github.com/mgomes/api_auth [Controllers & Models] https://github.com/danahartweg/authenticatable_rest_api


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...