Rails omniauth-weibo-oauth2 踩的第一个坑,谁有遇见?

void_dawn · 2016年10月31日 · 最后由 flemon1986 回复于 2016年11月02日 · 4458 次阅读

1.Gemfile 内添加如下 gem,并执行 bundle

gem "omniauth-oauth2"
gem "omniauth-weibo-oauth2"

2.(a) 添加了专门做第三方服务的 yml 文件,/confg/services.yml

common: &common
  weibo:
    api_key: "申请的key"
    api_secret: "申请的secret"
    redirect_uri: "http://127.0.0.1/users/auth/weibo/callback"
production:
  <<: *common
development:
  <<: *common
test:
  <<: *common

2.(b) 同时在 devise.rb 中这么写

SERVICES = YAML.load_file(Rails.root.join("config", "services.yml")).fetch(Rails.env)
Devise.setup do |config|
  config.omniauth :weibo, SERVICES['weibo']['api_key'], SERVICES['weibo']['api_secret']
end

3.由于用的 devise,所以 user.rb 做了如下更改

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  # devise :database_authenticatable, :registerable,
  #        :recoverable, :rememberable, :trackable, :validatable

  devise :database_authenticatable, :registerable,
         :recoverable,:rememberable,:validatable,
         :omniauthable, :omniauth_providers => [:weibo]

  has_many :orders       
end

4.以下是 devise 的 OmiauthCallbackController 的 code

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  # You should configure your model like this:
  devise :omniauthable, omniauth_providers: [:weibo]

  def weibo
    omniauth_process
  end

  protected
  def omniauth_process
    omniauth = request.env['omniauth.auth']
    authentication = Authentication.where(provider: omniauth.provider, uid: omniauth.uid.to_s).first

    if authentication
      set_flash_message(:notice, :signed_in)
      sign_in(:user, authentication.user)
      redirect_to root_path
    elsif current_user
      authentication = Authentication.create_from_hash(current_user.id, omniauth)
      set_flash_message(:notice, :add_provider_success)
      redirect_to authentications_path
    else
      session[:omniauth] = omniauth.except("extra")
      set_flash_message(:notice, :fill_your_email)
      redirect_to new_user_registration_url
    end
  end

  def after_omniauth_failure_path_for(scope)
    new_user_registration_path
  end

end

5.看看 rake routes 的结果

user_weibo_omniauth_authorize GET|POST /users/auth/weibo(.:format)                  devise/omniauth_callbacks#passthru
user_weibo_omniauth_callback GET|POST /users/auth/weibo/callback(.:format)         devise/omniauth_callbacks#weibo

6.open.weibo.com 中的配置

回调 redirect uirl 设置如下

7.微博登录后,合理的出现了授权界面,但是点击了授权后,没有达到理想的效果,返回如下 json error。

Started GET "/users/auth/weibo/callback?state=27f67b398054bd6d3e3d8f7ef6d65064c4b87d986784a7c8&code=[FILTERED]" for 127.0.0.1 at 2016-10-31 22:15:59 +0800
I, [2016-10-31T22:15:59.933569 #40827]  INFO -- omniauth: (weibo) Callback phase initiated.
E, [2016-10-31T22:15:59.991661 #40827] ERROR -- omniauth: (weibo) Authentication failure! invalid_credentials: OAuth2::Error, invalid_request: miss redirect uri.
{"error":"invalid_request","error_code":21323,"request":"/oauth2/access_token","error_uri":"/oauth2/access_token","error_description":"miss redirect uri."}

总结下,我除了应用的介绍图片没有完善,其他的设置都按照标准的设置走的,为什么 callback 的时候还说我 miss redirect uri?😅 😈 😅

应用地址必须是合法的域名,本地开发你可以改 hosts 或者用 pow

2 楼 已删除

#1 楼 @jasl 当时看帖子说如果是内网本地开发无域名,而且强调千万不要 localhost 要 127.0.0.1,并且测试通过…😂 你说的我试试吧

#1 楼 @jasl 我改 hosts 了,报错是一样的

#4 楼 @void_dawn 授权回调页的 URI,和你程序这边的路径也要一模一样,一般这种问题都是配置上的,没排查干净配置之前,不要轻信错误信息

#3 楼 @cx340090738 无域名就只能改 HOSTS 啦,当然 Pow 也好用,配合 powder 很方便

我想问 devise :omniauthable, omniauth_providers: [:weibo]不是应该在 user.rb 里吗?

哦,看你的代码,那个在 controller 里。。。

anyway 试试这个:

def weibo
  user = User.from_omniauth!(request.env["omniauth.auth"])
  sign_in_and_redirect user
end

还有,能 debug 一下,那个 weibo 方法是否真的被调用了

#6 楼 @jasl 我 open.weibo.com 的回调 uri 和程序里这个是一样的,还是谢了哎

#9 楼 @flemon1986 明显没有被调用

那,你能再确定一下你这句代码 devise :omniauthable, omniauth_providers: [:weibo]class User < ActiveRecord::Base 里面吗?

还有你的 route 是什么设置这个 omniauth_callbacks 的?

#12 楼 @flemon1986 我能确定 user.rb 里有 devise :omniauthable, omniauth_providers: [:weibo] 这句代码。还有 route 里我没设置关于 omniauth_callbacks,走 devise 默认的 devise_for :users

那你走过这个村,miss 掉这个店了, 改写devise_for :user这句成:

devise_for :user, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

#15 楼 @flemon1986 路由已配置 - - ,还是如下错误

ERROR -- omniauth: (weibo) Authentication failure! invalid_credentials: OAuth2::Error, invalid_request: miss redirect uri.
{"error":"invalid_request","error_code":21323,"request":"/oauth2/access_token","error_uri":"/oauth2/access_token","error_description":"miss redirect uri."}

提供的源代码有限,不知道怎么继续帮你 debug 了。。。

还有个疑点:

config.omniauth :weibo, SERVICES['weibo']['api_key'], SERVICES['weibo']['api_secret']

这句,里面缺了 redirect_uri 的设置

provider :weibo, ENV['WEIBO_KEY'], ENV['WEIBO_SECRET'],
         token_params: {redirect_uri: "http://127.0.0.1:3000/auth/weibo/callback" }

#18 楼 @flemon1986 恩,我的看法和您一致。

protected
     def build_access_token
       params = {
         'client_id' => client.id,
         'client_secret' => client.secret,
         'code' => request.params['code'],
         'grant_type' => 'authorization_code'
       }.merge(token_params.to_hash(symbolize_keys: true))
       client.get_token(params, deep_symbolize(options.auth_token_params))
     end

微博的用的是 auth_code 的 grant_type,所有在拿到 code 触发了回调之后,还要去拿 code 换 token。

这个过程中 code 和 redirect_url 都是必填项目,看 gem 代码似乎 redirect_url 还要额外配置。

#18 楼 @flemon1986 我基本就这些代码了,你说的缺了 redirect_uri 的设置,我用你的写了一样的报错,并且我看 devise.rb 是这样的

#19 楼 @akirapanda 这个授权按钮所在的表单信息里,什么都有。 以下是授权的表单

#19 楼 @akirapanda 我的目的是点授权,先到我的omniauth_callbacks#weibo里..有问题?我理解是,点授权后,api.weibo.com会带给我一个code到我本地的callback里,然后我才能用这个code和其他参数去拿token啊

#22 楼 @void_dawn 你方便贴一下 config/initializers/omniauth.rb 代码么,十有八九你 weibo provider 的配置问题

你看看初始化的时候有哪里配置过这个 redirect_url 么 我看你在自己的代码里没有配置 2.(b) 同时在 devise.rb 中这么写

SERVICES = YAML.load_file(Rails.root.join("config", "services.yml")).fetch(Rails.env)
Devise.setup do |config|
  # miss token_params
  config.omniauth :weibo, SERVICES['weibo']['api_key'], SERVICES['weibo']['api_secret']

#23 楼 @akirapanda 首先感谢你,这是我的 omniauth.rb

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :weibo, '1219785701', 'c44819c0063b76ba735ebf3436c5bdbd'
  # provider :qq_connect, 'App Key','App Secret'
  # provider :renren, 'App Key','App Secret'
end

目前配置 redirect_uri 的地方只有我的那个 yml 文件里....因为我着实不知道这个配置还配置在哪里。

#24 楼 @void_dawn provider 的第三个参数,你看着上图加一下应该就行了,weibo 这套有点非主流的。默认不用估计事因为 1.0 真的不用填。。。

#25 楼 @akirapanda 好吧,是个坑...我也总感觉缺点 redirect_uri 的配置。加上后,确实进到 callback 了,但是有点小问题。

OK, 如果我之前说的建议你都有了你现在代码差不多是这样:

# devise.rb
config.omniauth :weibo, SERVICES['weibo']['api_key'], SERVICES['weibo']['api_secret'], {
  token_params: { redirect_uri: "http://127.0.0.1/users/auth/weibo/callback" }
}
# route.rb
devise_for :user, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

这样还说 missing redirect uri, 我会在这个 gem omniauth-weibo-oauth2里这放个 debugger 看看究竟为啥 redirect_uri 没有 merge 进去

看来已经成功了,

疑点一:你在 devise.rb 里的配置和 omniauth.rb 里的配置一样的。。。应该一个就够了

疑点二:从错误提示来看,你的 gem 不是最新的,最新的第 58 行是这样的

image_size = options[:image_size] || :middle

#27 楼 @flemon1986 恩,你说的对。我现在看看目前存在的新问题吧。谢啦

NoMethodError (undefined method `to_sym' for nil:NilClass
Did you mean?  to_s):
  omniauth-weibo-oauth2 (0.4.1) lib/omniauth/strategies/weibo.rb:58:in `image_url'
  omniauth-weibo-oauth2 (0.4.1) lib/omniauth/strategies/weibo.rb:25:in `block in <class:Weibo>'
  omniauth (1.3.1) lib/omniauth/strategy.rb:105:in `instance_eval'

或者你给个:image_size 的配置来绕过这个错误

#28 楼 @flemon1986 哈哈哈哈,大师兄说的对!

#32 楼 @flemon1986 明天我再解决这个问题吧😈

ERROR -- omniauth: (weibo) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

请问你的 weibo 配置是在devise.rb里面吗 (omniauth.rb 删除了吗?)

  • 不是的话请试试删除掉omniauth.rb,在devise.rb里面配置 key, secret 和 redirect_uri
  • 是的话。。。再研究研究

#34 楼 @flemon1986 我最后用了 omniauth,没用 devise,两个留一个就行,ok 了,3q~~

void_dawn 关闭了讨论。 11月02日 15:03
void_dawn 重新开启了讨论。 11月02日 15:04
void_dawn 关闭了讨论。 11月02日 15:04
void_dawn 重新开启了讨论。 11月02日 15:04
void_dawn [该话题已被删除] 提及了此话题。 11月02日 15:18

ok,很好,解决了就好,更新一下原贴,mark 个已解决,让后人乘凉

void_dawn 关闭了讨论。 11月02日 22:15
需要 登录 后方可回复, 如果你还没有账号请 注册新账号