Reputation: 1271
I use the gem jwt
、devise
to build a user login system,
I generate a model Authentication to check the token exist or not.
follow this code:
models/authentication.rb
class Authentication < ApplicationRecord
def self.generate_access_token(email)
payload = {:email => email}
secret = 'secret'
token = JWT.encode payload, secret, 'HS256'
return token
end
end
controllers/user/sessions_controller.rb
def create
user = User.where(email: params[:email]).first
if user&.valid_password?(params[:password])
@token = Authentication.generate_access_token(user.email)
Authentication.create(access_token: @token)
authentications = {token: @token, email: user.email}
render json: authentications, status: :created
else
head(:unauthorized)
end
end
when I do a post request to user/sessions
I will get token and user email and store it in localstorage of client, and help me to check the token is valid.
follow this code:
def authenticate_token
token = Authentication.find_by_access_token(params[:token])
head :unauthorized unless token
end
In my question, are there ways to let token don't need to store into database?
Upvotes: 0
Views: 1183
Reputation: 8898
You can decode the token and get the email stored in it, and find user by that email.
Suppose you carry the token in the Authorization
header, like
Authorization: Bearer <token>
then you can define a before_action
to do this:
class ApplicationController < ActionController::API
before_action :authenticate_token
def authenticate_token
token = request.headers['Authorization'].to_s =~ /^Bearer (.*)$/i && $1
return head :unauthorized unless token
payload = JWT.decode(token, 'secret', true, algorithm: 'HS256')
user = User.find_by(email: payload['email'])
return head :unauthorized unless user
# TODO set the `user` as current_user
# How to patch devise's `current_user` helper is another story
end
end
If I were you, I would put user ID in the token, not email, because ID is shorter, and faster to lookup from database, and it exposes nothing personal to the internet (note that JWT is not encrypted. It's just signed).
Or you can skip all these messy things by just using knock instead of devise
.
Upvotes: 2