ruby-on-rails – Omniauth-Facebook:如何获得长期访问令牌?
我按照伟大的
Ryan Bates来帮助我设置ominauth-facebook,但在他的教程中他只展示了如何使用短期访问令牌(小时或2小时)进行设置.我们如何修改他的教程以使用长期访问令牌(60天)进行设置?
我一直在阅读Facebook docs about it和这个年纪较大的SO question. 这两个链接都建议添加一些这样的代码(尽管代码略有不同): GET /oauth/access_token? grant_type=fb_exchange_token& client_id={app-id}& client_secret={app-secret}& fb_exchange_token={short-lived-token} 人们会把它添加到哪里? 从我所看到的情况来看,似乎他们正在使它变得非常复杂.有人可以用初学者友好的语言吗? 让我们变得个性化. 我的代码与贝茨先生略有不同. 初始化/ ominauth.rb Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook,"1540352575225959","ee957abf5e851c98574cdfaebb1355f4",{:scope => 'user_about_me'} end 的routes.rb get 'auth/:provider/callback',to: 'sessions#facebook' sessions_controller def facebook user = User.from_omniauth(env["omniauth.auth"]) session[:user_id] = user.id redirect_to root_url end user.rb class User < ActiveRecord::Base acts_as_tagger acts_as_taggable has_many :notifications has_many :activities has_many :liked_comments,through: :comment_likes,class_name: 'Comment',source: :liked_comment has_many :valuation_likes has_many :habit_likes has_many :goal_likes has_many :stat_likes has_many :comment_likes has_many :authentications has_many :habits,dependent: :destroy has_many :levels has_many :valuations,dependent: :destroy has_many :comments has_many :goals,dependent: :destroy has_many :stats,dependent: :destroy has_many :results,through: :stats has_many :notes accepts_nested_attributes_for :habits,:reject_if => :all_blank,:allow_destroy => true accepts_nested_attributes_for :notes,:allow_destroy => true accepts_nested_attributes_for :stats,:allow_destroy => true accepts_nested_attributes_for :results,:allow_destroy => true has_many :active_relationships,class_name: "Relationship",foreign_key: "follower_id",dependent: :destroy has_many :passive_relationships,foreign_key: "followed_id",dependent: :destroy has_many :following,through: :active_relationships,source: :followed has_many :followers,through: :passive_relationships,source: :follower attr_accessor :remember_token,:activation_token,:reset_token before_save :downcase_email before_create :create_activation_digest validates :name,presence: true,length: { maximum: 50 },format: { with: /A[a-zsA-Z]+z/,message: "only allows letters" } VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-.]+.[a-z]+z/i validates :email,length: { maximum: 255 },format: { with: VALID_EMAIL_REGEX },uniqueness: { case_sensitive: false },unless: -> { from_omniauth? } has_secure_password validates :password,length: { minimum: 6 } def name read_attribute(:name).try(:titleize) end def count_mastered @res = habits.reduce(0) do |count,habit| habit.current_level == 6 ? count + 1 : count end end def count_challenged @challenged_count = habits.count - @res end def self.from_omniauth(auth) where(provider: auth.provider,uid: auth.uid).first_or_initialize.tap do |user| user.provider = auth.provider user.image = auth.info.image user.uid = auth.uid user.name = auth.info.name user.oauth_token = auth.credentials.token user.oauth_expires_at = Time.at(auth.credentials.expires_at) user.password = (0...8).map { (65 + rand(26)).chr }.join user.email = (0...8).map { (65 + rand(26)).chr }.join+"@mailinator.com" user.save! end end def self.koala(auth) access_token = auth['token'] facebook = Koala::Facebook::API.new(access_token) facebook.get_object("me?fields=name,picture") end # Returns the hash digest of the given string. def User.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string,cost: cost) end # Returns a random token. def User.new_token SecureRandom.urlsafe_base64 end # Remembers a user in the database for use in persistent sessions. def remember self.remember_token = User.new_token update_attribute(:remember_digest,User.digest(remember_token)) end # Forgets a user. NOT SURE IF I REMOVE def forget update_attribute(:remember_digest,nil) end # Returns true if the given token matches the digest. def authenticated?(attribute,token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end # Activates an account. def activate update_attribute(:activated,true) update_attribute(:activated_at,Time.zone.now) end # Sends activation email. def send_activation_email UserMailer.account_activation(self).deliver_now end def create_reset_digest self.reset_token = User.new_token update_attribute(:reset_digest,User.digest(reset_token)) update_attribute(:reset_sent_at,Time.zone.now) end # Sends password reset email. def send_password_reset_email UserMailer.password_reset(self).deliver_now end # Returns true if a password reset has expired. def password_reset_expired? reset_sent_at < 2.hours.ago end def good_results_count results.good_count end # Follows a user. def follow(other_user) active_relationships.create(followed_id: other_user.id) end # Unfollows a user. def unfollow(other_user) active_relationships.find_by(followed_id: other_user.id).destroy end # Returns true if the current user is following the other user. def following?(other_user) following.include?(other_user) end private def from_omniauth? provider && uid end # Converts email to all lower-case. def downcase_email self.email = email.downcase unless from_omniauth? end # Creates and assigns the activation token and digest. def create_activation_digest self.activation_token = User.new_token self.activation_digest = User.digest(activation_token) end end facebook.js.coffee.erb jQuery -> $('body').prepend('<div id="fb-root"></div>') $.ajax url: "#{window.location.protocol}//connect.facebook.net/en_US/all.js" dataType: 'script' cache: true window.fbAsyncInit = -> FB.init(appId: '<%= 1540372976229929 %>',cookie: true) $('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> window.location = '/auth/facebook/callback' if response.authResponse if $('#sign_out').length > 0 FB.getLoginStatus (response) -> window.location = $('#sign_out').attr("href") if !response.authResponse 资料来源:omniauth-facebook. “作为一名优秀的程序员,有3%的人才,97%的人不会被互联网分心.” 解决方法
我遇到了与之前正在构建的应用程序相同的问题.我发现的解决方案建议使用Koala身份验证在创建后立即延长初始短期令牌.
对我有用的解决方案的改编如下…… 首先,在Gemfile中包含gem’koala’,’2.0.0′.另外,访问Koala github site了解更多信息. 现在让我们将上面的内容应用于user.rb的from_omniauth方法…… def self.from_omniauth(auth) # Sets 60 day auth token oauth = Koala::Facebook::OAuth.new("1540352575225959","ee957abf5e851c98574cdfaebb1355f4") new_access_info = oauth.exchange_access_token_info auth.credentials.token new_access_token = new_access_info["access_token"] new_access_expires_at = DateTime.now + new_access_info["expires"].to_i.seconds where(provider: auth.provider,uid: auth.uid).first_or_initialize.tap do |user| user.provider = auth.provider user.image = auth.info.image user.uid = auth.uid user.name = auth.info.name user.oauth_token = new_access_token # auth.credentials.token <- your old token. Not needed anymore. user.oauth_expires_at = Time.at(auth.credentials.expires_at) user.password = (0...8).map { (65 + rand(26)).chr }.join user.email = (0...8).map { (65 + rand(26)).chr }.join+"@mailinator.com" user.save! end end 附加信息: 我还注意到您正在为用户的电子邮件和密码生成一些虚拟值.我建议您使用SecureRandom库这样做.虽然您的代码可能不会导致值的冲突,但至少对于我建议更改的电子邮件(0 … 8).map {(65 rand(26)).chr} .join“@mailinator .com“更稳定的SecureRandom.hex”@ mailinator.com“.如果您使用电子邮件作为在应用程序中记录用户的方式,这一点尤为重要. 我希望这能解决你的问题.最好的,蒂姆. 更新: 我很高兴我们能够回答你的问题并一起解决你所有的其他问题,但是这里有关于我之前谈论的代码重构的更新…… 考虑一种情况,即通过Facebook登录的用户在您的网站上更改自己的一些数据.假设他们改变了自己的名字,电子邮件或头像.这将正常工作,直到同一用户再次尝试重新登录.会发生什么是from_omniauth方法将再次被触发并覆盖这些更改.这很糟糕,防止这种情况的方法是做以下事情…… def self.from_omniauth(auth) . . . where(provider: auth.provider,uid: auth.uid).first_or_initialize.tap do |user| user.provider = auth.provider user.image = auth.info.image unless user.image != nil user.uid = auth.uid user.name = auth.info.name unless user.name != nil user.oauth_token = new_access_token user.oauth_expires_at = Time.at(auth.credentials.expires_at) user.password = SecureRandom.urlsafe_base64 unless user.password != nil user.email = SecureRandom.hex + "@mailinator.com" unless user.email != nil user.activated = true user.save! end 关键是使用除非user.image!= nil,它确保只有在初始值为:image为nil时才会设置图像.如果说用户更改了图像,则该值不会为nil,而from_omniauth将不会更改它.名称,电子邮件和密码也是如此.不要将它设置为其他任何东西. 另外,请注意我使用了SecureRandom.urlsafe_base64而不是你的(0 … 8).map {(65 rand(26)).chr} .join.这是因为urlsafe_base64生成一个随机的URL安全base64字符串,如i0XQ-7gglIsHGV2_BNPrdQ ==,它非常适合虚拟密码,看起来也很优雅. 另一方面,我使用十六进制用于电子邮件的原因是因为它创建了一个随机的十六进制字符串,如eb693ec8252cd630102fd0d0fb7c3485,如果碰巧有一些正则表达式来验证电子邮件(理想情况下你应该这样做),它不会破坏你的验证. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |