# Devise 中使用的 Middleware 是如何發揮作用的,跟 Warden 的關聯為何。
## Warden
Warden is a Rack-based middleware, designed to provide a mechanism for authentication in Ruby web applications. It is a common mechanism that fits into the Rack Machinery to offer powerful options for authentication.
## Rack
https://thoughtbot.com/upcase/videos/rack
1. 一種架構
2. 一個 gem
>Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.
1. Rack 封裝 HTTP requests 和 responses,所以我們可以用物件的方式使用 request 及產生 response
2. Rack 為 web servers,web frameworks 和介於兩者之間的軟體(所謂的 middleware)提供了統一的介面
3. Rack application 是一個具有 call 方法(接收 env 參數)的物件(統一的規格)
> 一個能夠回應 call 方法的物件,並且回傳一個包含以下三個元素的陣列:
> - HTTP 狀態(數字型態,例如正常回應是 200、找不到頁面是 404、伺服器錯誤是 500)。
> - HTTP Header(Hash 型態)。
> - Body(陣列型態,或是只要是個可以回應 each 方法的物件也可)。
### 架構:



## Middleware

Middleware 是一個術語,用於表示某種軟體,該軟體某種程度上與 Web application 的執行有關,但並不直接涉及所請求任務的執行。
Every Rack application is a class. The same applies to Rack middleware.

Rack middleware class 的規則:
1. initialize 方法的第一個參數是 application 或 the request handler
> the request handler has to be passed in the middleware class, so the middleware can wrap the execution of the application and do something to the request and the response of the application.
2. 具有 call 方法
> The call method executes the application which returns the status, the headers and the body of the response.
順序實驗:
```rb
# test_handler.ru
class MiddlewareTwo
def initialize(app)
@app = app
end
def call(env)
puts "MiddlewareTwo reporting in!"
puts "The app is: #{@app}"
puts "The has the methods: #{@app.methods - Object.methods}"
status, headers, body = @app.call(env)
[status, headers, body]
end
end
class MiddlewareOne
def initialize(app)
@app = app
end
def call(env)
puts "MiddlewareOne reporting in!"
puts "The app is: #{@app}"
puts "The has the methods: #{@app.methods - Object.methods}"
status, headers, body = @app.call(env)
[status, headers, body]
end
end
class HandlerClass
def self.call(env)
puts 'Handling the request...'
[200, { "Content-Type" => "text/html" }, ["<b>Request handled.</b>"]]
end
end
use MiddlewareTwo
use MiddlewareOne
run HandlerClass
```
執行 rackup test_handler.ru
```
Puma starting in single mode...
* Version 3.12.6 (ruby 2.3.7-p456), codename: Llamas in Pajamas
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:9292
Use Ctrl-C to stop
MiddlewareTwo reporting in!
The app is: #<MiddlewareOne:0x00007fbce85df348>
The has the methods: [:call]
MiddlewareOne reporting in!
The app is: HandlerClass
The has the methods: [:call]
Handling the request...
::1 - - [21/Feb/2021:23:09:48 +0800] "GET / HTTP/1.1" 200 23 0.0044
MiddlewareTwo reporting in!
The app is: #<MiddlewareOne:0x00007fbce85df348>
The has the methods: [:call]
MiddlewareOne reporting in!
The app is: HandlerClass
The has the methods: [:call]
Handling the request...
::1 - - [21/Feb/2021:23:09:48 +0800] "GET /robots.txt?1613920188911 HTTP/1.1" 200 23 0.0020
MiddlewareTwo reporting in!
The app is: #<MiddlewareOne:0x00007fbce85df348>
The has the methods: [:call]
MiddlewareOne reporting in!
The app is: HandlerClass
The has the methods: [:call]
Handling the request...
::1 - - [21/Feb/2021:23:09:49 +0800] "GET /favicon.ico HTTP/1.1" 200 23 0.0017
```
(第一個 middleware 的 app 是下一個 middleware,一層一層,直到 call 到最後一層 application)
## Devise
[devise.gemspec](https://github.com/heartcombo/devise/blob/master/devise.gemspec)
s.add_dependency("warden", "~> 1.2.3")
可得知 devise 有使用 warden 這個 gem
[RailsConf 2018: Warden: the building block behind Devise by Leonardo Tegon
](https://www.youtube.com/watch?v=QBJ3G40fxHg)
Devise 使用 warden 做為 devise 的 middleware
1. Devise 在驗證 user 是在 request 到達 rails application 之前就先做驗證,如果驗證失敗,request 根本不會到達 rails appliaction ?
2. Strategies 為 Warden 身份驗證邏輯撰寫的地方,Devise 添加 DatabaseAuthenticatable 做為基本的身份驗證邏輯

---
參考資料:
https://github.com/rack/rack
https://railsbook.tw/extra/rack.html
https://medium.com/ruby-on-rails-web-application-development/custom-400-500-error-pages-in-ruby-on-rails-exception-handler-3a04975e4677
https://www.rubyguides.com/2018/09/rack-middleware/
https://ruby-china.org/topics/31737
https://ieftimov.com/post/rack-first-principles/
https://ieftimov.com/post/writing-rack-middleware/
https://ieftimov.com/post/writing-rails-middleware/
https://softwarebrothers.co/blog/simple-warden-authentication-service/
https://speakerdeck.com/tegon/warden-the-building-block-behind-devise
https://www.ombulabs.com/blog/learning/devise/behind-the-scenes-devise.html
https://stackoverflow.com/questions/2256569/what-is-rack-middleware
---
其他參考資料:
https://thoughtbot.com/blog/back-to-basics-http-requests
https://5xruby.tw/posts/puma-zero-downtime/
https://github.com/rails/rails/blob/291a3d2ef2/railties/lib/rails/application/default_middleware_stack.rb
rails middleware
---
rails 最早期連 rack 都沒有
middleware 很像 reduce
AAA 協議