新浪微博oauth简单客户端实现_Ruby_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > Ruby > 新浪微博oauth简单客户端实现

新浪微博oauth简单客户端实现

 2010/12/30 8:05:58  酷的飞上天空  http://314858770.javaeye.com  我要评论(0)
  • 摘要:前后花了近一个星期,中间就sha1的加密就纠结了几天。。。还有一些莫名奇妙的问题,也都是自己的马虎,和对oauth认证的一知半解的原因。废话不多说,代码如下#coding:utf-8require"cgi"require"uri"require"net/http"require"openssl"require"base64"moduleOauth#注:暂不支持发布图片微博功能。##使用方法介绍#首先获取用户的授权,如果已获取授权则直接看第三步#1.首先取得未授权token
  • 标签:实现 新浪 客户 新浪微博 客户端 微博

前后花了近一个星期,中间就sha1的加密就纠结了几天。。。

还有一些莫名奇妙的问题,也都是自己的马虎,和对oauth认证的一知半解的原因。

?

废话不多说,代码如下

# coding: utf-8


require "cgi"


require "uri"


require "net/http"


require "openssl"


require "base64"


module Oauth


#注:暂不支持发布图片微博功能。


#


#使用方法介绍


#首先获取用户的授权,如果已获取授权则直接看第三步


#1.首先取得未授权token,使用get_request_token方法,然后跳转到新浪用户授权页面


#  def request_token


#    client = Oauth::Client.new({


#        :app_key => "3224168886",


#        :app_secret => "3739fb8b93b6c1737bd3052460a125e3"


#    })


#


#    token = client.get_request_token


#    session[:oauth_token_secret] = token[1]


#    # puts "=======================oauth_token_secret",session[:oauth_token_secret]


#    callback_url = "http://localhost:5000/oauth_test/access_token"


#


#    redirect_to client.authorize token[0],callback_url


#  end


#


#2.用户授权以后,通过callback_url返回自己的接收页面,接收已授权的token和oauth_verifier。使用已授权的token和其他参数获取用户的access_token和token_secret。


#这两个参数可以保存到数据库,以后就可以直接使用而不用再次走1和2的授权流程了,access_token和token_secret的有效期为直到用户登陆微博在设置里面取消授权为止


#    client = Oauth::Client.new({


#        :app_key => "3224168886",


#        :app_secret => "3739fb8b93b6c1737bd3052460a125e3"


#    })


#    render :text => client.get_access_token(params[:oauth_token], session[:oauth_token_secret],params[:oauth_verifier]).inspect


#


#3.使用授权过的token访问新浪的api接口例子如下


#


#    client = Oauth::Client.new({


#        :app_key => "3224168886",


#        :app_secret => "3739fb8b93b6c1737bd3052460a125e3",


#        :oauth_token => "you's oauth_token  ",


#        :oauth_token_secret => "you's oauth_token_secret",


#        :debug => true


#    })


#


#    client.send_request_get "http://api.t.sina.com.cn/direct_messages.json"  ## 获取当前用户最新私信列表


#    client.send_request_post "http://api.t.sina.com.cn/statuses/update.json",{:status=>CGI::escape("今天很暖和!!!")} ## 发送一条微博信息


#


  class Client


    attr_accessor :request_params





    ## :app_key 新浪的app_key


    ## :app_secret 新浪的app_secret


    ## :oauth_token 用户授权的access_token


    ## :oauth_token_secret 用户授权的oauth_token_secret


    ## :debug 是否输出具体的oauth参数,供查看调试


    def initialize(params)


      @request_params = {


        :request_token_url => "http://api.t.sina.com.cn/oauth/request_token",


        :access_token_url => "http://api.t.sina.com.cn/oauth/access_token",


        :authorize_url => "http://api.t.sina.com.cn/oauth/authorize",


        :oauth_consumer_key => params[:app_key],


        :oauth_consumer_secret => params[:app_secret],


        :oauth_token => params[:oauth_token],


        :oauth_token_secret => params[:oauth_token_secret],


        :debug => params[:debug]


      }


    end





    ## 此方法生成要跳出的页面url


    ## token 未授权的request_token


    ## callback_url 接受已授权token的url


    def authorize(token,callback_url)


      "#{@request_params[:authorize_url]}?oauth_token=#{token}&oauth_callback=#{CGI::escape(callback_url)}"


    end





    ## 获取未授权的token


    ## 返回参数为 [oauth_token,oauth_token_secret]


    ## 建议把oauth_token_secret存储到session或cookie,后面获取access_token的时候会使用


    ## 如果验证失败,则抛出异常。异常信息为新浪返回的错误字符串


    def get_request_token


    


      params = {


        :oauth_consumer_key => "#{@request_params[:oauth_consumer_key]}",


        :oauth_timestamp => Time.new.to_i.to_s,


        :oauth_nonce => (Time.new.to_i + 100).to_s,


        :oauth_version => "1.0a",


        :oauth_signature_method => "HMAC-SHA1"


      }	





      oauth_signature = digest base_string("GET",@request_params[:request_token_url],params)





      params_string = "#{query_string(params)}&oauth_signature=#{CGI::escape(oauth_signature)}"





      request_result = get_request_result(@request_params[:request_token_url],params_string)


      raise request_result if request_result.split("&").size != 2


      return [request_result.split("&")[0].split("=")[1],request_result.split("&")[1].split("=")[1]]


    end





    ## oauth_token 用后授权后返回的oauth_token


    ## oauth_token_secret 用后授权后返回的oauth_token_secret


    ## oauth_verifier 第一步中返回的oauth_verifier


    ## 返回为参数为[oauth_token,oauth_token_secret,user_id]


    ## 如果验证失败,则抛出异常。异常信息为新浪返回的错误字符串


    def get_access_token(oauth_token,oauth_token_secret,oauth_verifier)


      httpmethod = "GET"


      params = {


        :oauth_consumer_key => "#{@request_params[:oauth_consumer_key]}",


        :oauth_token => oauth_token,


        :oauth_timestamp => Time.new.to_i.to_s,


        :oauth_nonce => (Time.new.to_i + 100).to_s,


        :oauth_version => "1.0a",


        :oauth_signature_method => "HMAC-SHA1",


        :oauth_verifier => oauth_verifier


      }





      oauth_signature = digest base_string(httpmethod,@request_params[:access_token_url],params),@request_params[:oauth_consumer_secret]+"&"+oauth_token_secret


      params_string = "#{query_string(params)}&oauth_signature=#{CGI::escape(oauth_signature)}"


      request_result = get_request_result(@request_params[:access_token_url],params_string)


      result_array = request_result.split("&")


      raise request_result if result_array.size != 3


      return [result_array[0].split("=")[1],result_array[1].split("=")[1],result_array[2].split("=")[1]]


    end





    ## 发送GET请求,访问新浪api接口


    ## address 新浪api接口url,不含参数


    def send_request_get(address,data={})


      request_handle(address,data,"GET")


    end





    ## 发送POST请求,访问新浪api接口


    ## address 新浪api接口url,不含参数


    ## data 一个hash对象,里面的值如果包含特殊字符如请使用CGI::escape方法进行编码。


    def send_request_post(address,data={})


      request_handle(address,data,"POST")


    end





    private


    


    ## 用户访问新浪api接口


    ## address 新浪api接口url,不含参数


    ## data 一个hash对象,里面的值如果包含特殊字符如请使用CGI::escape方法进行编码。


    ## method 发出request请求的方式


    def request_handle(address,data,method="GET")





      params = {


        :oauth_consumer_key => "#{@request_params[:oauth_consumer_key]}",


        :oauth_nonce => (Time.new.to_i + 100).to_s,


        :oauth_signature_method => "HMAC-SHA1",


        :oauth_token => "#{@request_params[:oauth_token]}",


        :oauth_timestamp => Time.new.to_i.to_s,


        :oauth_version => "1.0a"


      }





      base_string_params = params.merge(data)


      


      oauth_signature = digest base_string(method,address,base_string_params),@request_params[:oauth_consumer_secret]+"&"+@request_params[:oauth_token_secret]





      params[:oauth_signature] = oauth_signature





      #生成http header 字符串


      header = {


        "Authorization" => "OAuth #{header_string(params)}"


      }





      uri = URI.parse(address)


      case method.to_s.upcase


      when "GET"


        req = Net::HTTP::Get.new(uri.path)


        req = Net::HTTP::Get.new(uri.path + "?#{query_string(data)}") if data.size != 0


      when "POST"


        req = Net::HTTP::Post.new(uri.path)


        #req.set_form_data(data)


        set_form_data(data,req,false)


        puts "===========post_body===========",req.body  if @request_params[:debug]


      else


        raise "no support request method!"


      end





      req["Authorization"] = header["Authorization"]  #设置http header





      res = Net::HTTP.start(uri.host,uri.port)do |http|


        http.request(req)


      end


      puts "===========request_reslult_body===========",res.body  if @request_params[:debug]


      return res.body if res.code == "200"   #如果返回状态码不为200,则表示访问失败。抛出返回失败的字符串


      raise res.body


    end





    ## 设置POST 方法的数据


    ## params post的参数, 一个hash对象


    ## request 要发出的Net::HTTP::Post对象


    ## escape 是否对post的内容进行再转义


    def set_form_data(params,request,escape=true)


      params_string = ""


      params.each do |k,v|


        params_string << "#{k.to_s}=#{CGI::escape(v.to_s)}&" if escape


        params_string << "#{k.to_s}=#{v.to_s}&" unless escape


      end


      params_string.chomp!("&")


      request["content_type"] = "application/x-www-form-urlencoded"


      request.body = params_string


    end





    ## 发出请求,只有获取用户验证的时候用到这个方法


    def get_request_result(request_token_url,params_string)


      url = URI.parse(request_token_url)


      res = Net::HTTP.start(url.host, url.port) {|http|


        http.get(url.path+"?#{params_string}")


      }


      puts "===========request_reslult_body===========",res.body  if @request_params[:debug]


      return res.body if res.code == "200"


      raise res.body


    end





    ## 使用HMAC-SHA1进行加密


    ## see http://stackoverflow.com/questions/1959486/digest-hmac-is-part-of-ruby-standard-lib


    def digest(value,key="#{@request_params[:oauth_consumer_secret]}&")


      puts "===========digest_key===========",key  if @request_params[:debug]


      signature = Base64.encode64 OpenSSL::HMAC.digest("SHA1", key, value)


      puts "===========signature===========",signature.strip  if @request_params[:debug]


      signature.strip


    end





    ## 生成http header字符串


    def header_string(header_params)


      result_string = ""


      header_params.to_a.sort{|a,b| a[0].to_s <=> b[0].to_s}.each do|param|


        result_string << "#{param[0]}=" << '"' << "#{CGI::escape(param[1])}"<< '",'


      end


      puts "===========header_string===========",result_string.chomp(",")  if @request_params[:debug]


      result_string.chomp(",")


    end





    ## 生成query_string 字符串


    def query_string(query_params)


      result_string = ""


      query_params.to_a.sort{|a,b| a[0].to_s <=> b[0].to_s}.each do|param|


        result_string << "#{param[0]}=#{CGI::escape(param[1])}&"


      end


      puts "===========query_string===========",result_string.chomp("&")  if @request_params[:debug]


      result_string.chomp("&")


    end





    ## 生成base_string 字符串


    def base_string(httpmethod,base_uri,request_params)


      base_str  = httpmethod + "&" + CGI::escape(base_uri) + "&" 


      base_str += request_params.to_a.sort{|a,b| a[0].to_s <=> b[0].to_s}.map{|param| CGI::escape(param[0].to_s) + "%3D"+ CGI::escape(param[1].to_s)}.join("%26")


      puts "===========base_string===========",base_str  if @request_params[:debug]


      base_str


    end





  end


end


?

暂时不能发送图片微博,这个功能以后在考虑。。。

?

同时发布到新浪微博论坛

http://forum.open.t.sina.com.cn/read.php?tid=558

上一篇: ruby 时间处理 下一篇: fog watching Sedum
发表评论
用户名: 匿名