Rails 来自本机 Android 应用的用户身份验证
Rails user authentication from native Android app
我正在尝试开发一个 Rails 应用程序,它主要与 Android 应用程序用户进行交流。人们应该能够在应用内注册和登录(他们只能在登录后执行大多数请求)。
我浏览了很多关于如何在应用程序上执行与 "storing a session" 等效的教程,但他们都推荐使用 gem 'devise'
及其 :token_authenticable
,这是已弃用 一段时间了。
我需要关于如何执行等效操作的严肃建议。根据我的理解,客户端发送带有 {email: "some@email.com", password: "pw12345"}
等参数的请求,我检查它们是否与现有用户匹配并检索字符串令牌,该客户端从现在开始将通过 headers 在每个请求中发送该令牌(例如{"my_app_user_email": "some@email.com", "my_app_user_token":"abcdef123456"}
)。
我已经设置了一些带有假值的方法,例如
def login
if valid_user?(params[:email], params[:password])
render json: {user_token: default_user_token}
else
render json: {message: 'Couldn\'t login'}, status: 401
end
end
其中default_user_token
是固定字符串,valid_user?
也是比较固定值
我想我的问题是知道这是否是正确的方法,如果是这样,我如何制作一个 User
模型来创建和验证令牌?
额外的代码
def verify_token # This already works by using default values in the Android app code
email = request.headers['HTTP_MY_APP_USER_EMAIL']
token = request.headers['HTTP_MY_APP_USER_TOKEN']
user = User.find_by_email(email)
user && user.valid_token?(token) # returns true for default_user_token, for now
end
我认为你的做法是正确的。您可以在模型中添加一个 auth_token 字段,并在用户登录时生成一个新字段。您可以像这样生成令牌:
def generate_authentication_token!
begin
self.auth_token = Devise.friendly_token
end while self.class.exists?(auth_token: auth_token)
end
你可以创建一个身份验证服务,要求对每个请求都提供用户令牌:
module Authenticable
#Devise overwritten method
def current_user
@current_user ||= User.find_by(auth_token: request.headers['Authorization'])
end
def authenticate_with_token!
render json: { errors: "Not authenticated" }, status: :unauthorized unless user_signed_in?
end
def user_signed_in?
current_user.present?
end
end
然后,您可以创建一个 SessionsController,使用以下设计注销 in/log 用户:
def create
user_password = params[:session][:password]
user_email = params[:session][:email]
user = user_email.present? && User.find_by(email: user_email)
if user
if user.valid_password? user_password
sign_in user, store: false
user.generate_authentication_token!
user.save
render json: user, root: :user, status: 200, location: [:api, user]
else
render json: { errors: "Invalid email or password" }, status: 422
end
else
render json: { errors: "Invalid email or password" }, status: 422
end
end
def destroy
user = User.find_by(auth_token: params[:id])
user.generate_authentication_token!
user.save
head 204
end
我在 github 上有这个使用这个解决方案的仓库:https://github.com/brunojppb/api_on_rails
我正在尝试开发一个 Rails 应用程序,它主要与 Android 应用程序用户进行交流。人们应该能够在应用内注册和登录(他们只能在登录后执行大多数请求)。
我浏览了很多关于如何在应用程序上执行与 "storing a session" 等效的教程,但他们都推荐使用 gem 'devise'
及其 :token_authenticable
,这是已弃用 一段时间了。
我需要关于如何执行等效操作的严肃建议。根据我的理解,客户端发送带有 {email: "some@email.com", password: "pw12345"}
等参数的请求,我检查它们是否与现有用户匹配并检索字符串令牌,该客户端从现在开始将通过 headers 在每个请求中发送该令牌(例如{"my_app_user_email": "some@email.com", "my_app_user_token":"abcdef123456"}
)。
我已经设置了一些带有假值的方法,例如
def login
if valid_user?(params[:email], params[:password])
render json: {user_token: default_user_token}
else
render json: {message: 'Couldn\'t login'}, status: 401
end
end
其中default_user_token
是固定字符串,valid_user?
也是比较固定值
我想我的问题是知道这是否是正确的方法,如果是这样,我如何制作一个 User
模型来创建和验证令牌?
额外的代码
def verify_token # This already works by using default values in the Android app code
email = request.headers['HTTP_MY_APP_USER_EMAIL']
token = request.headers['HTTP_MY_APP_USER_TOKEN']
user = User.find_by_email(email)
user && user.valid_token?(token) # returns true for default_user_token, for now
end
我认为你的做法是正确的。您可以在模型中添加一个 auth_token 字段,并在用户登录时生成一个新字段。您可以像这样生成令牌:
def generate_authentication_token!
begin
self.auth_token = Devise.friendly_token
end while self.class.exists?(auth_token: auth_token)
end
你可以创建一个身份验证服务,要求对每个请求都提供用户令牌:
module Authenticable
#Devise overwritten method
def current_user
@current_user ||= User.find_by(auth_token: request.headers['Authorization'])
end
def authenticate_with_token!
render json: { errors: "Not authenticated" }, status: :unauthorized unless user_signed_in?
end
def user_signed_in?
current_user.present?
end
end
然后,您可以创建一个 SessionsController,使用以下设计注销 in/log 用户:
def create
user_password = params[:session][:password]
user_email = params[:session][:email]
user = user_email.present? && User.find_by(email: user_email)
if user
if user.valid_password? user_password
sign_in user, store: false
user.generate_authentication_token!
user.save
render json: user, root: :user, status: 200, location: [:api, user]
else
render json: { errors: "Invalid email or password" }, status: 422
end
else
render json: { errors: "Invalid email or password" }, status: 422
end
end
def destroy
user = User.find_by(auth_token: params[:id])
user.generate_authentication_token!
user.save
head 204
end
我在 github 上有这个使用这个解决方案的仓库:https://github.com/brunojppb/api_on_rails