Rails API : 인증을 구현하는 가장 좋은 방법은 무엇입니까?


78

아직 개발되지 않은 모바일 앱용 API를 노출하는 Rails 4 앱을 작성 중입니다. 사용자는 모바일 앱에서 이메일과 비밀번호를 사용하여 인증합니다.

주제에 대한 많은 정보를 찾았습니다. 날짜가 지났거나 최적이 아닌 것을 식별하는 것은 어렵습니다. 너무 안전하지 않은 HTTP 기본 인증과 HTTP 토큰 기반 인증에 대해 읽었지만이를 일반 이메일 및 비밀번호 인증과 결합하는 방법을 잘 모르겠습니다 (Devise by 방법).

이를 구현하는 방법에 대한 현재 모범 사례가 무엇인지 알고 싶기 때문에 올바른 방향으로 진행할 것입니다.


1
세부 사항을 모르고 내 생각은 OAuth2입니다. 문지기 또는 oauth2 보석을 사용하십시오.
Joe Essey

답변:


49

보안 관점에서 중요한 점은 사용자의 이메일과 비밀번호를 토큰으로 한 번 교환 한 다음 해당 토큰을 후속 요청에 사용하는 것입니다. 이 때문입니다:

  1. 클라이언트 앱이 사용자의 암호를 유지하는 책임을지는 것을 원하지 않습니다. 버그 나 공격으로 인해 암호가 유출 될 수 있습니다. 과
  2. 서버에서 발급 한 토큰은 필요한 경우 토큰을 만료 할 수있는 기능을 제공합니다 (예 : 도난당한 장치를 잠 그거나 오작동하는 API 클라이언트를 차단).

다양한 수준의 복잡성으로이를 수행하는 방법에는 여러 가지가 있습니다.

다음은 토큰 기반 인증 (Devise를 사용하지 않지만 개념을 이해하는 데 여전히 관련이 있음)을 사용하여 Rails에서 API를 생성하기위한 매우 최근의 튜토리얼입니다. https://labs.kollegorna.se/blog/ 2015 / 04 / build-an-api-now /


감사! 이것이 내가 이해해야 할 것입니다.
Roma149

devise 토큰 외에도 장치 토큰을 사용할 수 있습니다. 이 답변 의 장치 토큰 은 장치를 올바르게 식별하는 데 도움이 될 수 있으며 다른 장치가 웹 사이트에 액세스하는 경우 도움이 될 수 있습니다.
duykhoa

5

또 다른 옵션은 아래 모듈을 devise MODEL에 포함시키고 auth_token을 테이블에 추가하는 것입니다.

app / models / concerns / token_authenticable.rb

module TokenAuthenticatable
  extend ActiveSupport::Concern

  included do
    before_save :ensure_auth_token
  end

  module ClassMethods
    def find_by_token(token)
      find_by(auth_token: token)
    end
  end

  def ensure_auth_token
    self.auth_token = generate_auth_token if auth_token.blank?
  end

  private

  def generate_auth_token
    loop do
      token = Devise.friendly_token
      break token unless self.class.exists?(auth_token: token)
    end
  end
end

app / controllers / api / v1 / login_controller.rb

...
 def login_user(params)
    if params[:authentication]
      @user = User.find_by(auth_token: params[:authentication])
      if @user.nil?
        render json: err('login user by token failed', ERR_USER_NOT_FOUND), status: :not_found
        event('login_user_by_auth_failed', 'token', params[:authentication])
        return
      else
        render status: :ok, json: @user
        return
      end
    else
      user = user.find_by(email: params[:email])
      if user.nil?
        event('login_user_failed_not_found', 'user_email', params[:email])
        render json: err("login user not found #{params[:email]}", ERR_USER_NOT_FOUND), status: :not_found
        return
      end
      if user.access_locked?
        event('login_user_blocked', 'user_id', user.id)
        render json: err("login user account is locked : #{user.id}", ERR_USER_LOCKED), status: :unauthorized
        return
      end
      unless user.try(:valid_password?, params[:password])
        event("login_user_password_does_not_match #{user.id}", 'user_id',  user.id)
        render json: err('login user password does not match', ERR_PASSWORD_NOT_MATCH), status: :unauthorized
        return
      end
      event('login_user_succeeded', 'user_id', user.id)
      @user= user
      if @user.save
        response.headers['authentication'] = @user.auth_token
        render status: :ok, json: @user
        return
      else
        render json: @user.errors, status: :unprocessable_entity
        return
      end
    end
  end
...

편집 : 수정 된 코드 브레이킹 오타


뿐만 아니라 레일의 has_secured_password 기능과 모양이
마술

token_authenticable이 더 이상 사용되지 않는다고 생각합니다.
Kelsey Hannan

4

@ Roma149 이것은 개인적인 선호도이지만 막 시작한 대부분의 사람들은 가장 쉬운 IMO이기 때문에 Devise를 사용합니다. OAuth2도 좋은 옵션입니다. 더 중요한 메모로 언제든지 The Ruby Toolbox 로 이동할 수 있습니다.

보석에 대한 좋은 정보가 많이 있으며 보석의 나이와 인기도 알려줍니다. 이것은 또한 커뮤니티가 지금 정말로 괴롭히는 보석이나 오래된 보석을 구별 할 수있게 해줍니다.

Ruby와 Ruby On Rails에서는 항상 더 나은 gem이 아니라 프로젝트에 가장 적합한 것이 무엇인지 기억하세요!


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.