---
# System prepended metadata

title: '[Rails4][jwt]rails jwt簡易實作'
tags: [jwt, Rails4]

---

# [Rails4][jwt]rails jwt簡易實作

###### tags: `Rails4`,`jwt`


參考資料:
https://jwt.io/

https://mgleon08.github.io/blog/2018/07/16/jwt/

https://github.com/jwt/ruby-jwt

https://github.com/riskimidiw/rails-jwt/tree/e6bbb582010d760f78f0260f45906374041b154c

https://medium.com/binar-academy/rails-api-jwt-authentication-a04503ea3248






>原則上是參考這篇[教學](https://medium.com/binar-academy/rails-api-jwt-authentication-a04503ea3248),
>步驟基本上差不多,所以不再詳述,
>只是有幾點不同:
>1. 未用 --api參數產生api專案,這部份其實我覺得沒啥差別
>2. token 解密跟加密的方式採用HS256
>3. 把bcrypt拿掉,使用明碼儲存,以便簡化範例
>4. 把應該是給未來上傳頭像功能用的程式碼省略
>5. 有使用plain html(放在public資料夾)實作簡單前端去測試jwt


## Routes

>這部份跟教學完全一樣,未做更動

config/routes.rb
```ruby
Rails.application.routes.draw do
  
  resources :users,param: :_username
  post '/auth/login', to: 'authentication#login'
  get '/*a', to: 'application#not_found'

end

```
## Model

>user model內的程式碼全部拿掉,
>那些跟bcrypt與圖像上傳有關



## Controller


>hmac_secret變數是secret key,應該要放在environment中,
>此處僅作為示範用,所以寫在controller內

application_controller.rb
```ruby
class ApplicationController < ActionController::Base
  

  def not_found
    render json: { error: 'not_found' }
  end
    
    #jwt加解密的語法跟教學不同
    #參考https://jwt.io/
  def authorize_request
        token = request.headers['Authorization']

        hmac_secret = 'my$ecretK3y'

        begin
          @decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
          data= @decoded_token[0]
          @current_user=User.find_by(id: data["user_id"])
          render json: {user: @current_user}

        rescue ActiveRecord::RecordNotFound => e
          render json: { errors: e.message }, status: :unauthorized
        rescue JWT::DecodeError => e
          render json: { errors: e.message }, status: :unauthorized
        end

    end


 
end

```


authentication_controller.rb
```ruby
class AuthenticationController < ApplicationController
  before_action :authorize_request, except: :login

  def login
    
    
    @user=User.find_by(email: params[:user][:email],password: params[:user][:password])
    
    if @user
      payload={user_id: @user.id}
      hmac_secret = 'my$ecretK3y'

      token = JWT.encode payload, hmac_secret, 'HS256'
      render json:{token: token}

    else
      render json:{error:'unauthorized'}
    end

  end

  private

  def login_params
    params.permit(:email, :password)
end
end

```


users_controller.rb
```ruby
class UsersController < ApplicationController

  before_action :authorize_request, except: :create
  before_action :find_user, except: %i[create index]

  # GET /users
  def index
    @users = User.all
    render json: @users, status: :ok
  end

  # GET /users/{username}
  def show
    render json: @user, status: :ok
  end

  # POST /users
  def create
    @user = User.new(user_params)
    if @user.save
      render json: @user, status: :created
    else
      render json: { errors: @user.errors.full_messages },
             status: :unprocessable_entity
    end
  end

  # PUT /users/{username}
  def update
    unless @user.update(user_params)
      render json: { errors: @user.errors.full_messages },
             status: :unprocessable_entity
    end
  end

  # DELETE /users/{username}
  def destroy
    @user.destroy
  end

  private

  def find_user
    @user = User.find_by_username!(params[:_username])
    rescue ActiveRecord::RecordNotFound
      render json: { errors: 'User not found' }, status: :not_found
  end

  def user_params
    params.require(:user).permit(:name, :username, :email, :password)
    
  end
end

```


## View(此處指放在public資料夾的html)

> 1.未使用postman,改採用plain html的方式去測試,
> 這部份在實務上應該是要用前端框架諸如Angular,React,VUe
> 去實作前端,此處省略.
> 2.請開啟瀏覽器的主控台視窗查看回傳結果
 



index.html
```htmlembedded=
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>index page</title>
  
  <!-- jquery -->
  <script
			  src="https://code.jquery.com/jquery-3.4.1.min.js"
			  integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
			  crossorigin="anonymous"></script>
		
</head>
<body>

  <H2>user login</H2>
  <form>
    email<input type="text" id="email"><br>
    password<input type="password" id="password"><br>
  
    <button onclick="userLogin()">submit</button>
  
  
  </form>
  
  <script>
  
    function userLogin(){
      
      //需加上這句以避免form進行自動提交
      event.preventDefault();
      
      $.ajax({
        
        url: "/auth/login",
        type: "POST",
        contentType: 'application/json',
        dataType: "json",
        data:JSON.stringify({
          user:{
            "email":$("#email").val(),
            "password":$("#password").val(),
          }
       }),
        success: function(data) {
          console.log("success!!");
          console.log(data);
        },
        
        error: function(err) {
          console.log("ERROR!!!");
          console.log(err.status);
          console.log(err);
        }
      });
    }
  
  </script>





</body>
</html>

```

login.html
```htmlembedded=

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>index page</title>
  
  <!-- jquery -->
  <script
			  src="https://code.jquery.com/jquery-3.4.1.min.js"
			  integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
			  crossorigin="anonymous"></script>
		
</head>
<body>

  <H2>user login</H2>
  <form>
    email<input type="text" id="email"><br>
    password<input type="password" id="password"><br>
  
    <button onclick="userLogin()">submit</button>
  
  
  </form>
  
  <script>
  
    function userLogin(){
      
      //需加上這句以避免form進行自動提交
      event.preventDefault();
      
      $.ajax({
        
        url: "/auth/login",
        type: "POST",
        contentType: 'application/json',
        dataType: "json",
        data:JSON.stringify({
          user:{
            "email":$("#email").val(),
            "password":$("#password").val(),
          }
       }),
        success: function(data) {
          console.log("success!!");
          console.log(data);
        },
        
        error: function(err) {
          console.log("ERROR!!!");
          console.log(err.status);
          console.log(err);
        }
      });
    }
  
  </script>





</body>
</html>


```



register.html

```htmlembedded=

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>index page</title>
  
  <!-- jquery -->
  <script
			  src="https://code.jquery.com/jquery-3.4.1.min.js"
			  integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
			  crossorigin="anonymous"></script>
		
</head>
<body>

  <H2>user register</H2>
  <form>
    name<input type="text" id="name"><br>
    username<input type="text" id="username"><br>
    email<input type="text" id="email"><br>
    password<input type="password" id="password"><br>
    password confirm<input type="password" id="password_confirmation"><br>
  
    <button onclick="userCreate()">submit</button>
  
  
  </form>
  
  <script>
  
    function userCreate(){
      
      //需加上這句以避免form進行自動提交
      event.preventDefault();

      $.ajax({
        
        url: "/users",
        type: "POST",
        contentType: 'application/json',
        dataType: "json",
        data:JSON.stringify({
          user:{
            "name":$("#name").val(),
            "username":$("#username").val(),
            "email":$("#email").val(),
            "password":$("#password").val(),
            "password_confirmation":$("#password_confirmation").val(),
          }
       }),
        success: function(data) {
          console.log("success!!");
          console.log(data);
        },
        
        error: function(err) {
          console.log("ERROR!!!");
          console.log(err.status);
          console.log(err);
        }
      });
    }
  
  </script>





</body>
</html>


```


test_auth.html

>可將取得的token貼在input中並按提交,查看回傳結果

```htmlembedded=

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>index page</title>
  
  <!-- jquery -->
  <script
			  src="https://code.jquery.com/jquery-3.4.1.min.js"
			  integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
			  crossorigin="anonymous"></script>
		
</head>
<body>

  <H2>test user token</H2>
  <form>
    token<input type="text" id="token"><br>
  
    <button onclick="testToken()">submit</button>
  
  
  </form>
  
  <script>
  
    function testToken(){
      
      //需加上這句以避免form進行自動提交
      event.preventDefault();

      token=$("#token").val();
      
      
      $.ajax({
        beforeSend: function(request) {
          request.setRequestHeader("Authorization", token);
        },
        
        url: "/users",
        type: "GET",
        success: function(data) {
          console.log("success!!");
          console.log(data);
        },
        
        error: function(err) {
          console.log("ERROR!!!");
          console.log(err.status);
          console.log(err);
        }
      });
    }
  
  </script>





</body>
</html>


```



