前后端分离之后,关于鉴权方式的选择里,除了传统的使用 session 之外,还可以使用 jwt_token 来鉴权,尤其是手机端的项目,使用 jwt_token 鉴权有以下好处
在前端登录成功后,会把 jwt_token 返回给前端,而前端之后每次访问都会在 header 里面加一条 (Authorization: Bearer XXXX),XXXX 就是放置 jwt_token 的位置
详细的结构可以看这里,我这里就简单的概括一下 jwt 分为三段
三段数据全部用 Base64 加密,然后用.
来隔开,就生成了 jwt_token,一般会长这样
eyJhbGciOiJIUzI1NiJ9.eyJleHBfYXQiOiIyMDE5LTEwLTA2IDE3OjU3OjU0ICswODAwIiwiaWQiOjQsInVzZXJuYW1lIjoi57qq5Lqa55Cq77yI6LaF566h77yJIiwidXNlcl90eXBlIjoic3VwZXJfYWRtaW4iLCJtb2JpbGUiOiIxNzcyMTI3MzIzMyJ9.38VDrWZlDmAY4fiYmJo-_rDKhYzaxEwiewj9ruyVSCQ
该 token 的安全保障其实全靠那个私钥(其实基于 https 完全不用考虑安全问题),当前端试图更改 payload 信息来登录其他账号时,由于他不知道对称加密要用到的私钥,因此他无法生成正确的第三段信息,因此他无法通过服务器的验证
gem 'jwt'
$ bundle install
可以放在 user 模型里,这个随意 生成 jwt_token 的方法 user.rb
class User < ApplicationRecord
def generate_jwt_token
hmac_secret = JWT_HMAC_SECRET ##服务器的私钥,可以是一个字符串或者钥匙,这个自己决定
payload = {
exp_at: (Time.now + 1.week).to_s,
id: id,
username: username,
user_type: user_type,
mobile: mobile
}
JWT.encode payload, hmac_secret, 'HS256'
end
...
验证方法
def self.decoded_jwt_infos token
JWT.decode(token, JWT_HMAC_SECRET, true, { algorithm: 'HS256' })[0]
end
在控制器层,写 current_user 方法
class Api::ApiController < ApplicationController
skip_before_action :verify_authenticity_token
def check_login
if current_user.blank?
render json: {msg: "登录失败", result: false}, status: :forbidden
end
end
def current_user
if request.headers['Authorization']&.start_with?("Bearer")
jwt_token = request.headers['Authorization'].split&.last
jwt_info = User.decoded_jwt_infos(jwt_token)
if Time.parse(jwt_info["exp_at"]) > Time.now
@current_user ||= User.unscoped.active.find_by_id(jwt_info["id"])
end
end
rescue JWT::ExpiredSignature, JWT::VerificationError
nil
end
end
剩下的就是在登录成功后将生成的 token 返回,可以放在 body 里,也可以放在 headers 里,这个随意