新手问题 Ruby on Rails Tutorial 的疑问:Sign out 沒有用 DELETE 方法也可以?

artone · September 20, 2012 · Last by gonglexin replied at September 20, 2012 · 3204 hits

最近照著 Ruby on Rails Tutorial 做练习,遇到了一些无法理解的疑问:

书里实现 sign out 功能的方法如下:

这是 view 的 sign out 按钮,signout_path 对应的是 sessions#destroy

<%= link_to "Sign out", signout_path, method: "delete" %>

sessions_controller 的 destroy 方法:

def destroy
  sign_out
  redirect_to root_path
end

这是在 helper 实现的 sign_out 方法:

def sign_out
  self.current_user = nil
  cookies.delete(:remember_token)
end

我的疑问是,重做的时候发现自己 view 里少了:

method: "delete"

但是 sign in 和 sign out 仍然运作良好,那我不晓得为何书上要加上这段代码呢?

routes 怎么写的?

#1 楼 @ywencn

跟这部份有关的 route:

resources :sessions, :only => [:new, :create, :destroy]
match "/signout", :to => "sessions#destroy"

不加的话是可以,不过就不遵循 RESTful 了,最好加上吧,这样也会安全点,你的 routes 是不是配置了match ':controller(/:action(/:id))(.:format)'之类的,所以才能匹配到 sign_out 这个 action。

#2 楼 @artone match "/signout", :to => "sessions#destroy"这里用到了match就能接收到 get 请求了

#4 楼 @Zernel 大概懂意思,我再思考一下,感谢!

明白了,刚又翻了一下书里的代码,原来书里 route 用的是:

match "/signout", :to => "sessions#destroy", via: :delete

所以才要加 method: "delete",不过我现在又想,如果有人伪造一个 DELETE 请求的连结,点下去不就被 sign out 了吗?这安全性该如何周全?看完了书里那个章节,也没提到该怎么预防。

这个和安全性无关... RESTFul 就是动作 (4 种动词的请求) + 资源 主要是设计路由的

#6 楼 @artone 谁伪造自己 signout 啊

#6 楼 @artone 伪造很难,Rails 自带了 CSRF 保护机制,可以看 jquery_ujs.js 里面有这样的代码

handleMethod: function(link) {
      var href = rails.href(link),
        method = link.data('method'),
        target = link.attr('target'),
        csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content'),
        form = $('<form method="post" action="' + href + '"></form>'),
        metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';

      if (csrf_param !== undefined && csrf_token !== undefined) {
        metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
      }

      if (target) { form.attr('target', target); }

      form.hide().append(metadata_input).appendTo('body');
      form.submit();
    },

除非伪造的人能够得到这个 csrf-token

match "/signout", :to => "sessions#destroy", via: :delete

delete 'signout' => 'sessions#destroy'

You need to Sign in before reply, if you don't have an account, please Sign up first.