JWT 构建Rails API 授权登录


参考下面的连接
使用Rails构建JSON-API
https://chorder.net/2018/07/31/使用Rails构建JSON-API/

安装jwt组件

Gemfile里添加

# jwt
gem 'jwt'

执行命令:

bundle install

创建base_controller.rb控制器

这个控制器的代码就会位于app/controllers/api/v1/base_controller.rb,我们需要在其中完善一些权限有关的配置。

由于Rails默认的安全属性,以及我们如果之前自定义了一些控制器中的过滤方法,我们需要在该控制器中跳过它,例如我们首先禁用rails自带的CSRF 保护和CSRF token的输出,以及去除掉返回包中的set-cookies头,由于我的应用还使用了devise作为用户认证的模块,所以还要在此禁用掉authenticate_user方法。
完整的代码如下

新建一个控制器
rails g controller api/v1/base --no-assets

class Api::V1::BaseController < ApplicationController
  # disable the CSRF token
  # protect_from_forgery with: :null_session

  # disable cookies (no set-cookies header in response)
  # before_action :destroy_session
  before_action :check_login


  # disable the CSRF token
  skip_before_action :verify_authenticity_token

  # skip devise user authentication
  # skip_before_action :authenticate_user!
  # skip_before_action :authenticate_admin!

  # def destroy_session
  #   request.session_options[:skip] = true
  # end


  @current_user

  def check_login
    puts "request.path222 #{request.path}"
    unless ["/api/v1/login"].include?(request.path)
      @current_user = current_user1()
      if @current_user.blank?
        # render json: {msg: "登录失败", result: false}, status: :forbidden
        render json: { statusCode: 4001, messages: "token验证失败,请重新登陆.", data: [] }
      end
    end
  end

  def current_user1
    if request.headers['Authorization']&.start_with?("Bearer")
      jwt_token = request.headers['Authorization'].split&.last
      # puts "jwt_token11:#{jwt_token}"
      jwt_info = Token::decoded_jwt_infos(jwt_token)
      # puts "jwt_info11:#{jwt_info}"
      user = User.find_by(id: jwt_info["user_id"])
      # puts "jwt_info222:#{jwt_info}"
      if Time.parse(jwt_info["exp_at"]) > Time.now && user.present?
        user
      else
        nil
      end
    end
  rescue JWT::ExpiredSignature, JWT::VerificationError
    nil
  end

end

创建好base控制器以后,我们需要在这个控制器的基础上派生出一些新的控制器,这里我们新建一个login_controller.rb控制器

rails g controller api/v1/login`` --no-assets

此时除了会生成控制器代码以外,还会在app/views/api/v1目录下创建login目录,作为模板存放的目录。

login控制器的代码位于app/controllers/api/v1/login_controller.rb,内容如下


class Api::V1::LoginController < Api::V1::BaseController
  def index
    # Token.decoded_jwt_infos()
    puts "logins index"
  end

  def create
    puts "params[password]:#{params[:password]}"
    user = User.find_by(username: params[:username])
    unless user.present?
      # flash.now[:notice] = "用户名不存在"
      # render :index and return
      render json: { statusCode: 4002, messages: "用户名不存在", data: [] }
      return
    end
    unless user.valid_password?(params["password"])
      render json: { statusCode: 4003, messages: "用户名或密码错误",data:[]}
      return
    end

    if user.category.blank? || user.category != "super_admin"
      render json: { statusCode: 4004, messages: "用户没有权限",data:[]}
      return
    end
    # render json: payload(@member)
    data = {
             id: user.id,
             username: user.username,
             category: user.category,
             token: Token.encode(user) }
    render json: { statusCode: 200, messages: "SUCCESS", data: data }

  end

  def check_token
    puts "#{Time.now} @check_token22->:#{@current_user.to_json}"
    user = @current_user
    puts "#{Time.now} user333:#{user.to_json}"
    # Token.decoded_jwt_infos()
    # user = current_user
    # @user = User.find(params[:id])
    data = {
      id: user.id,
      username: user.username,
      category: user.category }
    render json: { statusCode: 200, messages: "ok", data: data }
  end
end

配置路由

接下来我们对路由config/routes.rb进行配置

  namespace :api do
    namespace :v1 do
      resources :login, only: [:create] do
        collection do
          post :check_token
        end
      end
    end
  end

启动Rails程序

rails s

用户登陆-api接口

访问接口
访问http://127.0.0.1:3000/api/v1/login,即可看到接口输出的JSON数据。

curl -X POST 'http://10.10.11.133:8080/api/v1/login' \
--header 'Content-Type: application/json' \
--data '{
	"username": "admin",
	"password":"123456"
}'

响应示例
成功响应示例

{

    "statusCode": 200,
    "messages": "SUCCESS",
    "data": {
        "id": 1, //用户id
        "username": "admin", //用户登陆名
        "category": "super_admin", //角色类型:super_admin:超级管理员
        "token": "eyJhbGciOiJIUzI1NiJ9.eyJleHBfYXQiOiIyMDIyLTAxLTE3IDExOjU5OjU4ICswODAwIiwidXNlcl9pZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.Fens2VDYy8Br6FyEtcCyMa4caUWrfGcGr2gLtu77dCM" //登陆token
    } //返回数据

}

验证用户token信息-api接口(*)

curl --location --request POST 'http://10.10.11.133:8080/api/v1/login/check_token' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHBfYXQiOiIyMDIyLTAxLTE3IDExOjU5OjU4ICswODAwIiwidXNlcl9pZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.Fens2VDYy8Br6FyEtcCyMa4caUWrfGcGr2gLtu77dCM'

响应示例
成功响应示例

{

    "statusCode": 200,
    "messages": "SUCCESS",
    "data": {
        "id": 1, //用户id
        "username": "admin", //用户登陆名
        "category": "super_admin" //角色类型:super_admin:超级管理员
   } //返回数据

}
posted @ 2021-08-19 14:42  HaimaBlog  阅读(244)  评论(0编辑  收藏  举报