<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6196740086027153447</id><updated>2024-08-29T05:58:21.257-07:00</updated><title type='text'>核驚慌！仁嚇壞！</title><subtitle type='html'>太恐怖了..我再也不碰改改程式就要重開機的事情了..</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mudmerb.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://mudmerb.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>contagion</name><uri>http://www.blogger.com/profile/13677354681517903830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm3.static.flickr.com/2048/1808481797_c2339dd049_s.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6196740086027153447.post-5540259824299775252</id><published>2008-11-11T02:13:00.000-08:00</published><updated>2008-11-11T03:41:48.456-08:00</updated><title type='text'>Merb-Auth (4) 討厭的 Google OpenID (其實 Yahoo 更討厭)</title><content type='html'>&lt;span style=&quot;font-size:100%;&quot;&gt;為什麼說他們討厭呢？其實是因為他們不支援簡單好用的  &lt;a href=&quot;http://openid.net/specs/openid-simple-registration-extension-1_0.html&quot;&gt;SReg&lt;/a&gt; ，所以即使是登入成功，也拿不到使用者的個人資訊。&lt;/span&gt;還好 Google 還支援 &lt;a href=&quot;http://openid.net/specs/openid-attribute-exchange-1_0.html&quot;&gt;AX &lt;/a&gt; (不過現在也只能拿到 email)，Yahoo 的話，就只好乖乖的去用 &lt;a href=&quot;http://developer.yahoo.com/auth/&quot;&gt;BBAuth&lt;/a&gt; 了。&lt;br /&gt;&lt;br /&gt;這篇文章就來擴充一下 default_openid 的功能，讓它也可以支援 google。&lt;br /&gt;&lt;br /&gt;首先我們在 login form 上加上 &quot;用google&quot; 登入的按鈕：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;&amp;lt;div&gt;&lt;br /&gt;&amp;lt;form action=&quot;&amp;lt;%= slice_url(:merb_auth_slice_password, :perform_login) %&gt;&quot; method=&quot;POST&quot; accept-charset=&quot;utf-8&quot;&gt;    &amp;lt;input type=&quot;hidden&quot; name=&quot;_method&quot; value=&quot;PUT&quot; /&gt;&lt;br /&gt; &amp;lt;div class=&quot;formRow&quot;&gt;&lt;br /&gt;   &amp;lt;input type=&quot;submit&quot; name=&quot;google_openid_url&quot; value=&quot;用 GOOGLE 帳號登入&quot; id=&quot;google_openid_url&quot;&gt;&lt;br /&gt; &amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt;&amp;lt;/form&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;/pre&gt;再來編輯 merb/merb-auth/strategies.rb ，多加上一個  GoogleOpenID strategy：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;require &#39;openid/extensions/ax&#39;&lt;br /&gt;class GoogleOpenID &amp;lt; Merb::Authentication::Strategies::Basic::OpenID&lt;br /&gt;def run!&lt;br /&gt;  if params[:google_openid_url]&lt;br /&gt;    identity_url = &#39;https://www.google.com/accounts/o8/id&#39;&lt;br /&gt;    begin&lt;br /&gt;      openid_request = consumer.begin(identity_url)&lt;br /&gt;      openid_ax = ::OpenID::AX::FetchRequest.new&lt;br /&gt;      ax_info = ::OpenID::AX::AttrInfo.new(&#39;http://axschema.org/contact/email&#39;,&#39;email&#39;,true)&lt;br /&gt;      openid_ax.add(ax_info)&lt;br /&gt;      openid_request.add_extension(openid_ax)&lt;br /&gt;      redirect!(openid_request.redirect_url(&quot;#{request.protocol}://#{request.host}&quot;, openid_callback_url))&lt;br /&gt;    rescue ::OpenID::OpenIDError =&gt; e&lt;br /&gt;      request.session.authentication.errors.clear!&lt;br /&gt;      request.session.authentication.errors.add(:openid, &#39;The OpenID verification failed&#39;)&lt;br /&gt;      nil&lt;br /&gt;    end &lt;br /&gt;  end &lt;br /&gt;end &lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;GoogleOpenID 只是繼承了 OpenID，然後將 run! 的部份改寫成，當發現 params 中有 google_openid_url 時，就發出一個 openid 的 request 給 google 的 server，原本 SReg 去要 nickname/email 的部份則改成用 AX 來要 email。這個 Strategy 是一定不會回傳登入物件的，因為 google 導回來我們的程式時，相關的參數會被 OpenID 那個 Strategy，所以我們也要將他稍微的改寫：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;  def on_success!(response, sreg_response)&lt;br /&gt;   if user = find_user_by_identity_url(response.identity_url)&lt;br /&gt;     user&lt;br /&gt;   else&lt;br /&gt;     user = user_class.new&lt;br /&gt;     unless user.login        = sreg_response.data[&#39;nickname&#39;]&lt;br /&gt;       ax_response = ::OpenID::AX::FetchResponse.from_success_response(response)&lt;br /&gt;       user.login = ax_response.data[&quot;http://axschema.org/contact/email&quot;][0] if ax_response&lt;br /&gt;       user.login.sub!(/@.*/,&#39;&#39;) if user.login&lt;br /&gt;     end&lt;br /&gt;&lt;br /&gt;     user.identity_url = response.identity_url&lt;br /&gt;     user.password = user.password_confirmation = Digest::SHA1.hexdigest(&quot;#{response.identity_url}#{rand(1000)}&quot;)&lt;br /&gt;     user.save ? user : nil&lt;br /&gt;   end  &lt;br /&gt; end&lt;/pre&gt; 我們只改寫 on_success! 的部份。一開始先判斷是否已經用 SReg 取得了 nickname 和 email 了，如果拿不到的話，再用 AX 試試看能不能拿到 email，再將 email 的 @ 之前的部份暫且當做是 nickname，其它的部份就和原來的 OpenID 相同了。&lt;br /&gt;&lt;br /&gt;其實要這樣寫應該是原本的 default_openid 不夠彈性。應該是在發出 OpenID request 給 OpenID Provider 之前提供一個 callback 讓使用者可以設定不同的需求才對。</content><link rel='replies' type='application/atom+xml' href='http://mudmerb.blogspot.com/feeds/5540259824299775252/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/6196740086027153447/5540259824299775252' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/5540259824299775252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/5540259824299775252'/><link rel='alternate' type='text/html' href='http://mudmerb.blogspot.com/2008/11/merb-auth-4-google-openid-yahoo.html' title='Merb-Auth (4) 討厭的 Google OpenID (其實 Yahoo 更討厭)'/><author><name>contagion</name><uri>http://www.blogger.com/profile/13677354681517903830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm3.static.flickr.com/2048/1808481797_c2339dd049_s.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6196740086027153447.post-3726053090369787503</id><published>2008-11-10T12:30:00.000-08:00</published><updated>2008-11-11T02:13:34.764-08:00</updated><title type='text'>Merb-Auth (3) 再來一種 Strategy</title><content type='html'>&lt;a href=&quot;http://mudmerb.blogspot.com/2008/11/merb-auth-2.html&quot;&gt;上一篇&lt;/a&gt;講了設定和簡單的流程原理。這一篇又要來寫些程式&lt;br /&gt;先來看看最基本的 Strategy 大概的樣子：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;class MyStrategy &amp;lt; Merb::Authentication::Strategy&lt;br /&gt;def run!&lt;br /&gt;#這裡要寫登入的邏輯，成功時傳回登入物件，失敗時傳回 false 或 nil&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;每個 Strategy 都會繼承 Merb::Authentication::Strategy 這個 class，並且有一個名為 run! 的 method。當 Merb-Auth 要 Login 時，就會一個一個 Strategy 的去跑這個 Method。當此 method 回傳一個非 false 的值時，Merb-Auth 認為登入成功。如果失敗的話，可以回傳 nil/false ，或者也可直接 redirect! 到某個位置，對過接下來其它的 Strategy (OpenID 就是這麼做的)。&lt;br /&gt;&lt;br /&gt;讓我們把 Hello World 加上 OpenID 的功能吧！&lt;br /&gt;首先要改變一下 User model，將 app/models/user.rb 加上一個 property，用來存此使用者所用的 openid：&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;property :identity_url, String, :length =&gt; 256&lt;/pre&gt;在 app/views/exceptions/unauthenticated.html.erb 加上 openid 專用的 form：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;&amp;lt;div&gt;&lt;br /&gt;&amp;lt;form action=&quot;&amp;lt;%= slice_url(:merb_auth_slice_password, :perform_login) %&gt;&quot; method=&quot;POST&quot; accept-charset=&quot;utf-8&quot;&gt;&lt;br /&gt;&amp;lt;input type=&quot;hidden&quot; name=&quot;_method&quot; value=&quot;PUT&quot; /&gt;&lt;br /&gt;&amp;lt;div class=&quot;formRow&quot;&gt;&lt;br /&gt;  &amp;lt;label&gt;OpenID&lt;br /&gt;    &amp;lt;input type=&quot;text&quot; name=&quot;openid_url&quot; value=&quot;&quot; id=&quot;openid_url&quot;&gt;&lt;br /&gt;  &amp;lt;/label&gt;&lt;br /&gt;&amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt;&amp;lt;div class=&quot;formRow&quot;&gt;&lt;br /&gt;  &amp;lt;input type=&quot;submit&quot; name=&quot;Submit&quot; value=&quot;登入&quot; id=&quot;Submit&quot;&gt;&lt;br /&gt;&amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt;&amp;lt;/form&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;/pre&gt;這個 form 最主要是讓使用者輸入他的 openid 到 openid_url 這個 field 裡去，其它都照抄原來的 password form。&lt;br /&gt;&lt;br /&gt;最後在 merb/merb-auth/strategies.rb 裡加上這幾行：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;Merb::Authentication.activate!(:default_openid)&lt;br /&gt;class Merb::Authentication::Strategies::Basic::OpenID&lt;br /&gt;def openid_callback_url&lt;br /&gt;  &quot;#{request.protocol}://#{request.host}/&quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def on_success!(response, sreg_response)&lt;br /&gt;  if user = find_user_by_identity_url(response.identity_url)&lt;br /&gt;    user&lt;br /&gt;  else&lt;br /&gt;    user = user_class.new&lt;br /&gt;    user.login       = sreg_response.data[&#39;nickname&#39;]&lt;br /&gt;    user.identity_url = response.identity_url&lt;br /&gt;    user.password  = user.password_confirmation = Digest::SHA1.hexdigest(&quot;#{response.identity_url}#{rand(1000)}&quot;)&lt;br /&gt;    user.save ? user : nil&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;第一行是將 default_openid 這個 strategy 開啟。接下來是 overwrite 它的一些 default 設定。&lt;br /&gt;&lt;br /&gt;openid_callback_url 的回傳值是給 openid provider redirect back 用的。基本上就是一個需要 login 的 url，我們的例子中就用 http://localhost:4000/ 就可以了。&lt;br /&gt;&lt;br /&gt;openid provider 回傳此使用者可以登人後，就會呼叫 on_success! 。&lt;br /&gt;首先我們先用 find_user_by_identity_url 去找有沒有這個 user object，如果就就表示此人曾經用這個 openid  登入過，直接回值這個 user 就好了。如果沒有的話，就用建立一個新的使用者。(這裡這麼做是為了簡化起見，正式的做法應該是 redirect! 到一個註冊的頁面，讓使用者可以輸入/更改一些像是暱稱、生日之類的訊息。)&lt;br /&gt;&lt;br /&gt;這樣就寫好了 opendid 支援。</content><link rel='replies' type='application/atom+xml' href='http://mudmerb.blogspot.com/feeds/3726053090369787503/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/6196740086027153447/3726053090369787503' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/3726053090369787503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/3726053090369787503'/><link rel='alternate' type='text/html' href='http://mudmerb.blogspot.com/2008/11/merb-auth-3-strategy.html' title='Merb-Auth (3) 再來一種 Strategy'/><author><name>contagion</name><uri>http://www.blogger.com/profile/13677354681517903830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm3.static.flickr.com/2048/1808481797_c2339dd049_s.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6196740086027153447.post-23417755304522496</id><published>2008-11-10T09:13:00.000-08:00</published><updated>2008-11-10T12:31:34.862-08:00</updated><title type='text'>Merb-Auth (2) 來龍去脈</title><content type='html'>&lt;a href=&quot;http://mudmerb.blogspot.com/2008/11/merb-auth-1-tutorial.html&quot;&gt;上一篇&lt;/a&gt;我們快速生了一個有 login 功能的 merb app。這一篇要來好解釋一下這些東西的來龍去脈，還有各種可以設定的地方。&lt;br /&gt;&lt;br /&gt;首先看看有哪些設定檔。(這裡可能講的有些零亂，不過先看過去，等把下面流程的部份對照一下就應該蠻清楚了。)&lt;br /&gt;&lt;br /&gt;在 config/dependencies.rb 可以看到下面這三行：&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;dependency &quot;merb-auth-core&quot;, merb_gems_version&lt;br /&gt;dependency &quot;merb-auth-more&quot;, merb_gems_version&lt;br /&gt;dependency &quot;merb-auth-slice-password&quot;, merb_gems_version&lt;br /&gt;&lt;/pre&gt;Merb-Auth 和 Merb 一樣，依據必要性的不同，分成三個部份。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;merb-auth-core 包含了最基本的功能，像是上一篇講到的 session.user 或是 ensure_authenticated 這些做登入一定會用到的東西。&lt;/li&gt;&lt;li&gt;merb-auth-more 包含了一些好用的功能，像是已經寫好的三種登入方式(http-basic / password / openid)，登入完可以導回原本要去的頁面的 redirect_back_or 等等。&lt;/li&gt;&lt;li&gt;merb-auth-slice-password 則是一個 slice 。slice 是 merb 的一個超強大功能，可以把他想成是一個小型的 app，讓你可以隨意的整合進其它的 app 裡面。我們上一篇，在我們還沒有寫 login form 的 view (app/views/exceptions/unauthenticated.html.erb) 時 ，用的就是這個 slice 已經幫我們寫好的！&lt;/li&gt;&lt;/ul&gt;預設是這三樣東西通通都啟用。如果你不想用某個部份，可以直接在這裡把他們 comment 掉。&lt;br /&gt;&lt;br /&gt;接下來另一個重要的設定檔是 merb/merb-auth/setup.rb：&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;# Merb::Plugins.config[:&quot;merb-auth&quot;][:login_param]    = :email &lt;br /&gt;# Merb::Plugins.config[:&quot;merb-auth&quot;][:password_param] = :my_password_field_name&lt;/pre&gt;這兩行原本是被 comment 起來。它們是用來設定登入時所用的欄位名稱。預設是用 login/password，不過大家應該比較喜歡 username/password 吧！&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;Merb::Authentication.user_class = User&lt;/pre&gt;這行設定的是登入物件的 class 。所謂的登入物件就是你要用什麼物件來代表登入的這個人。像有人會喜歡用 Person / Account 之類的。&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;require &#39;merb-auth-more/mixins/salted_user&#39;&lt;br /&gt;Merb::Authentication.user_class.class_eval{ include Merb::Authentication::Mixins::SaltedUser }&lt;/pre&gt;這兩行將 salted password 的邏輯加到了剛剛設定的登入物件 class 裡面。如果你去翻一下上一篇我們的程式，在 app/models/user.rb 裡，你會看到並沒有設定 crypted_password，salt 等欄位，可是生出來的 User object 卻有，就是因為這兩行啦！&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;class Merb::Authentication&lt;br /&gt;&lt;br /&gt;def fetch_user(session_user_id)&lt;br /&gt;  Merb::Authentication.user_class.get(session_user_id)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def store_user(user)&lt;br /&gt;  user.nil? ? user : user.id&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;這幾行是告訴 Merb-Auth 怎麼從 session 中取得的東西轉換成登入物件(fetch_user)，或是怎麼從登入物件轉換成 session 中所存的東西(store_user)。因為有這個設定的關係，你的登入物件可以和 database 完全沒有關係，甚至只是一個 Boolean 都可以(就是只有登入和沒登入兩種情況，不管登入的人是誰)。預設的 fetch_user 是用 datamapper 去資料庫拿物件出來，如果你用的是 AR 就要改這裡了。&lt;br /&gt;&lt;br /&gt;還有一另一個設定檔 merb/merb-auth/strategies.rb&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;Merb::Authentication.activate!(:default_password_form)&lt;br /&gt;Merb::Authentication.activate!(:default_basic_auth)&lt;/pre&gt;這裡是將 default_password_form 和 default_basic_auth 這兩個登入的方式啟動。如果你想用別的認證方式，像是 openid / ldap / AD 之類的，就可以寫在這裡。&lt;br /&gt;&lt;br /&gt;接下來我們來解釋一下整個登入的流程。&lt;br /&gt;&lt;br /&gt;當我們要去看一個需要登入才能看的頁面時(例子中的 /hello/index 或是 /hello/wazzap )，Merb-Auth 會先看看 session[:user] 是否有東西，有的話表示已經登入了。如果沒有登入的話，它會用各種的方式去登入。這些方式被稱為 Strategies，也就是在 merb/merb-auth/strategies.rb 裡設定的東西。&lt;br /&gt;&lt;br /&gt;這些 Strategy 可以取得 Request 的各種參數(cookie/session/url/route/params...)，用它們來判斷這個 session 是不是可以成功的登入。當某一個 Strategy 成功時，Merb-Auth 會用設定的 store_user 將 user 存進 session 裡，這樣下一次 request 再來時就可以直接跳過登入的過程了。&lt;br /&gt;&lt;br /&gt;當所有的 Strategies 都失敗的時候，Merb-Auth  並不像 Rails 一般的做法，丟一個 302 redirect 到登入的 action 去，而是直接丟  401 Unauthorized 錯誤出來。(你可以用 firebug 去看他的 response status code。別告訴我你沒裝這個 &lt;a href=&quot;http://getfirebug.com/&quot;&gt;WebDeveloper 最好的朋友&lt;/a&gt;。)&lt;br /&gt;&lt;br /&gt;那為什麼 401 錯誤會有個 login 的 form 呢？這就是 merb 好玩的地方了！當程式執行中發生的 Exception，都會被 merb 自己 catch 起來，幫他放一個 status code ，然後 re-route 到 app/controllers/exceptions.rb 的某個 action 去。 Merb-Auth 發出來的 Exception 是自己定義的 Unauthenticated，它的 status code 401 ，而對應到的 action 就是 Exceptions#unauthenticated 了。&lt;br /&gt;&lt;br /&gt;這個 controller 和一般的 controller 沒什麼兩樣，也可以用 layout，可以用 before/after filter，可以用 template。merb-auth-slice-password 貼心的(或者應該說是雞婆的)幫我們準備了 Exceptions#unauthenticated 這個 aciton 還有它的 view 。所以你如果要改變登入 form 樣子，就自己寫 app/controllers/exceptions.rb 的 unauthenticated 這個 method 和 app/views/exceptions/unauthenticated.html.erb 這個 file 吧。&lt;br /&gt;&lt;br /&gt;這一篇我們說明了 Merb-Auth 大致的原理，下一篇就幫我們的 Hello 加上 OpenID 的支援。</content><link rel='replies' type='application/atom+xml' href='http://mudmerb.blogspot.com/feeds/23417755304522496/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/6196740086027153447/23417755304522496' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/23417755304522496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/23417755304522496'/><link rel='alternate' type='text/html' href='http://mudmerb.blogspot.com/2008/11/merb-auth-2.html' title='Merb-Auth (2) 來龍去脈'/><author><name>contagion</name><uri>http://www.blogger.com/profile/13677354681517903830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm3.static.flickr.com/2048/1808481797_c2339dd049_s.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6196740086027153447.post-1826281589227214252</id><published>2008-11-10T06:41:00.000-08:00</published><updated>2008-11-10T12:31:53.734-08:00</updated><title type='text'>Merb-Auth (1) 快速上手</title><content type='html'>幾乎每個 WebApp 一開始要都是先把登入登出做起來吧？&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Merb-Auth 是 Merb 預設的 Authentication framework，非常的彈性，和一般 Rails 的做法(對，就是 restful_authetication 和他的徒子徒孫)，相當的不同。MerbAuth 它只做一件事：&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-weight: bold;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:x-large;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: rgb(255, 0, 0);&quot;&gt;登入&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。所以&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: rgb(255, 0, 0);&quot;&gt;有關使用者管理、像是註冊，認證email、重設密碼之類的，事通通要你自己來&lt;/span&gt;。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;這一篇文章我們先完全用 Merb 初始的設定，來完成一個有登入功能的 HelloWorld，下篇我們再慢慢解釋其中的原理，如何做各種的設定。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;首先，產生一個新的 merb app&lt;/div&gt;&lt;pre name=&quot;&#39;code&#39;&quot;&gt;$ merb-gen app hello_world&lt;br /&gt;$ cd hello_world&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;merb-gen 出來的程式，預設就會開啟 Merb-Auth 的功能，使用 username/password 的認證方式，它會假設你要用 User 這個 model，所以就幫你建好在 app/models/user.rb 裡了。&lt;/div&gt;&lt;pre name=&quot;&#39;code&#39;&quot;&gt;$ rake db:automigrate&lt;/pre&gt;&lt;div&gt;這會將 User model 的 schema 寫到 db 裡。因為 MerbAuth 並沒有註冊的功能，所以我們先手動建立一個 user：&lt;/div&gt;&lt;pre name=&quot;&#39;code&#39;&quot;&gt;$ merb -i&lt;br /&gt;&gt;&gt; u = User.new(:login =&gt; &quot;new_user&quot;)&lt;br /&gt;&gt;&gt; u.password = u.password_confirmation = &quot;12345&quot;&lt;br /&gt;&gt;&gt; u.save&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;接下來我們隨便產生一個頁面，就叫它 /hello/index 吧：&lt;/div&gt;&lt;pre name=&quot;&#39;code&#39;&quot;&gt;$ merb-gen controller hello&lt;/pre&gt;&lt;div&gt;然後修改 config/routes.rb，把首頁指到 /hello/index 去：&lt;/div&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;Merb::Router.prepare do&lt;br /&gt;slice(:merb_auth_slice_password, :name_prefix =&gt; nil, :path_prefix =&gt; &quot;&quot;)&lt;br /&gt;authenticate do&lt;br /&gt; match(&#39;/&#39;).to(:controller =&gt; &#39;hello&#39;, :action =&gt;&#39;index&#39;)&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;&lt;div&gt;用 authenticate do ... end 將 route 包住，就會讓它必需要登入才能看到。&lt;/div&gt;&lt;div&gt;這樣就好了！啟動 server&lt;/div&gt;&lt;pre name=&quot;&#39;code&#39;&quot;&gt;$ merb&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;用 browser 開啟 http://localhost:4000/ 就會看到登入的畫面。&lt;br /&gt;&lt;/div&gt;&lt;div&gt;輸入正確的 username/password (我們的例子中是 new_user/12345) 後，就會看到 hello/index 的內容。&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;登入後，我們可以用 session.user 取得 user object。讓我們修改一下 app/view/hello/index.html.erb，可以看到登入者的名字，順便也把登出的 link 做上去：&lt;/div&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;&amp;lt;div&gt;Hello!!! &amp;lt;%= session.user.login %&gt;&amp;lt;/div&gt;&lt;br /&gt;&amp;lt;%= link_to &quot;登出&quot;, url(:logout) %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;除了用 authenticate 來包住 route 之中，也可以用 before filter 的方式，在 app/controllers/hello.rb 再加上一個 action：&lt;/div&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;before :ensure_authenticated, :only =&gt; &#39;wazzap&#39;&lt;br /&gt;def wazzap&lt;br /&gt;&quot;wazzap!! #{session.user.login}&quot;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;還有那個登入的 form  實在是太醜了！想要改變的話，可以寫這個檔案 app/views/exceptions/unauthenticated.html.erb：&lt;/div&gt;&lt;pre name=&quot;code&quot; class=&quot;ruby&quot;&gt;&lt;br /&gt;&amp;lt;h3&gt;還是很醜的登入 FORM&amp;lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div&gt;&lt;br /&gt;&amp;lt;%= session[:return_to].inspect %&gt;&lt;br /&gt;&amp;lt;%= error_messages_for session.authentication %&gt;&lt;br /&gt;&amp;lt;% @login_param = Merb::Authentication::Strategies::Basic::Base.login_param %&gt;&lt;br /&gt;&amp;lt;% @password_param = Merb::Authentication::Strategies::Basic::Base.password_param %&gt;&lt;br /&gt;&amp;lt;form action=&quot;&amp;lt;%= slice_url(:merb_auth_slice_password, :perform_login) %&gt;&quot; method=&quot;POST&quot; accept-charset=&quot;utf-8&quot;&gt;&lt;br /&gt;&amp;lt;input type=&quot;hidden&quot; name=&quot;_method&quot; value=&quot;PUT&quot; /&gt;&lt;br /&gt; &amp;lt;div class=&quot;formRow&quot;&gt;  &lt;br /&gt;      &amp;lt;label&gt;帳號:&lt;br /&gt;           &amp;lt;input type=&quot;text&quot; name=&quot;&amp;lt;%= @login_param.to_s %&gt;&quot; value=&quot;&quot; id=&quot;&amp;lt;%= @login_param.to_s %&gt;&quot;&gt;     &lt;br /&gt;      &amp;lt;/label&gt;&lt;br /&gt; &amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt; &amp;lt;div class=&quot;formRow&quot;&gt;  &lt;br /&gt;      &amp;lt;label&gt;密碼:&lt;br /&gt;           &amp;lt;input type=&quot;password&quot; name=&quot;&amp;lt;%= @password_param.to_s %&gt;&quot; value=&quot;&quot; id=&quot;&amp;lt;%= @password_param.to_s %&gt;&quot;&gt;&lt;br /&gt;      &amp;lt;/label&gt;&lt;br /&gt; &amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt; &amp;lt;div class=&quot;formRow&quot;&gt;&lt;br /&gt;      &amp;lt;input type=&quot;submit&quot; name=&quot;Submit&quot; value=&quot;登入&quot; id=&quot;Submit&quot;&gt;&lt;br /&gt; &amp;lt;/div&gt; &amp;lt;!-- close: formRow --&gt;&lt;br /&gt;&amp;lt;/form&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;/pre&gt;下一篇我們會解釋為什麼這個 form 的位置這麼的奇怪。</content><link rel='replies' type='application/atom+xml' href='http://mudmerb.blogspot.com/feeds/1826281589227214252/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/6196740086027153447/1826281589227214252' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/1826281589227214252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6196740086027153447/posts/default/1826281589227214252'/><link rel='alternate' type='text/html' href='http://mudmerb.blogspot.com/2008/11/merb-auth-1-tutorial.html' title='Merb-Auth (1) 快速上手'/><author><name>contagion</name><uri>http://www.blogger.com/profile/13677354681517903830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm3.static.flickr.com/2048/1808481797_c2339dd049_s.jpg'/></author><thr:total>0</thr:total></entry></feed>