0

Delphi 有没有实现,它连接到 twitter 新 API,1.1,并在 twitter 上进行操作?

他们还删除了所有 xml 支持,因此需要有 json 操作。

来自推特网站的解释:

首先我们需要像这样设置一个 indy 连接:

POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEJvZzpMOHFxOVBaeVJn
                     NmllS0dFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip

grant_type=client_credentials

然后我们可以使用 indy 来获取 twitter 响应:

HTTP/1.1 200 OK
Status: 200 OK
Content-Type: application/json; charset=utf-8
...
Content-Encoding: gzip
Content-Length: 140

{"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAAAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}

这看起来很简单,但是我们需要使用 ssl,它强制不使用wireshark 进行调试。

我使用的代码:

Uses EncdDecd;
Const
  Consumer_Key  = 'xvz1evFS4wEEPTGEFPHBog';
  Consumer_Secret   = 'L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg';
  Host = 'api.twitter.com/';
  Request_token_URL = 'https://api.twitter.com/oauth/request_token';
  Twitter_Content_Type = 'application/x-www-form-urlencoded;charset=UTF-8';
var
  Response:TStream;
  twittersite:TIdHttp;// assume on Form
  Trace:TMemo; //assume on Form
  IdSSLIOHandlerSocketOpenSSL1:TIdSSLIOHandlerSocketOpenSSL;//assume on Form
function EncodeBase64String(s: string): string;
var
 sIn:TSTringSTream;
begin
  sIn := TStringStream.create(s);
  result := String (EncodeBase64(Sin.Memory, sIn.Size));
  sin.Free;
end;
begin
  Response:= TMemoryStream.Create;
  try
    //Headers
    twittersite.Request.Host := Host;
    twitterSite.Request.UserAgent := 'Fucy Town 1.0';
    twitterSite.Request.CustomHeaders.Add('Authorization=Basic '+EncodeBase64String(Consumer_Key+':'+Consumer_Secret));
    twitterSite.Request.ContentType := Twitter_Content_Type;
    twitterSite.Request.CustomHeaders.Add('grant_type=client_credentials');
   //SSL
    twitterSite.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
    TwitterSite.Post(Request_token_URL,response);

    Trace.Lines.LoadFromStream(Response);
  finally
    FreeAndNil(Response);
  end;
end;

这导致 401 未经授权。

可以做些什么来修复此代码并获得 200 ok?

4

1 回答 1

0

倾倒

unit twitter;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdIntercept, IdLogBase, IdLogDebug, IdIOHandler, IdIOHandlerSocket,
  IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdHTTP, StdCtrls, IdCoder, IdCoder3to4,
  IdCoderMIME;
const
//https://dev.twitter.com/docs/auth/application-only-auth
  URL =  'https://api.twitter.com/oauth2/token';
  key = 'xvz1evFS4wEEPTGEFPHBog'; //this is example, replace with yours. 
  secret = 'L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg';//this is example, replace with yours. 
type
  TForm5 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    IdHTTP1: TIdHTTP;
    IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
    IdLogDebug1: TIdLogDebug;
    IdEncoderMIME1: TIdEncoderMIME;
    procedure IdLogDebug1Receive(ASender: TIdConnectionIntercept;
      var ABuffer: TBytes);
    procedure IdLogDebug1Send(ASender: TIdConnectionIntercept;
      var ABuffer: TBytes);
    procedure Button1Click(Sender: TObject);
  private
    parameters:TStringList;
    ringBear:string;
    keySecretBase64:string;
    procedure initConnection;
    function getRingBear(input:TStringstream):string;
    function requestRingBear:TStringStream; //bearer token
    procedure requestTwits;
    function logoff:TStringStream;
  public
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

uses IdGlobal, superobject;

procedure TForm5.initConnection;
begin
    with IdSSLIOHandlerSocketOpenSSL1 do begin
      SSLOptions.Method := sslvSSLv3;
      SSLOptions.Mode :=  sslmUnassigned;
      SSLOptions.VerifyMode := [];
      SSLOptions.VerifyDepth := 2;
    end;
    with IdHTTP1 do begin
      IOHandler := IdSSLIOHandlerSocketOpenSSL1;
      ReadTimeout := 0;
      AllowCookies := True;
      ProxyParams.BasicAuthentication := False;
      ProxyParams.ProxyPort := 0;
      Request.ContentLength := -1;
      Request.ContentRangeEnd := 0;
      Request.ContentRangeStart := 0;
      Request.ContentType := 'application/x-www-form-urlencoded';
      Request.Accept := 'text/html, */*';

      Request.BasicAuthentication := False;
      Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
      HTTPOptions := [hoForceEncodeParams];
    end;
    IdHTTP1.Intercept := IdLogDebug1;
    parameters.Clear;
    IdHTTP1.Request.CustomHeaders.Clear;

end;
function TForm5.logoff:TStringStream;
begin 
  result := TStringStream.Create;
  idhttp1.Request.CustomHeaders.AddValue('Authorization','Basic '+keySecretBase64);
  parameters.Add('access_token='+ringBear);
  IdHTTP1.Post('https://api.twitter.com/oauth2/invalidate_token',parameters,result);
  keySecretBase64:='';
  ringBear := '';
end; //the caller needs to free the stream

function TForm5.requestRingBear:TStringStream;
begin
  result := TStringStream.create;
  keySecretBase64 := TIdEncoderMIME.EncodeString(key+ ':' + secret, IndyTextEncoding_UTF8);
  parameters.Add('grant_type=client_credentials');
  Memo1.Lines.Add('secret and key ' + keySecretBase64);
  IdHTTP1.Request.CustomHeaders.AddValue('Authorization','Basic '+keySecretBase64);
  IdHTTP1.post(URL,parameters,result);
end;//the caller needs to free the stream

procedure TForm5.requestTwits;
begin
  IdHTTP1.Request.CustomHeaders.AddValue('Authorization','Bearer ' + ringBear);
  memo1.lines.add('twits response : ' +
    IdHTTP1.Get('https://api.twitter.com/1.1/statuses/user_timeline.json?count=100&screen_name=twitterapi'));

end;

procedure TForm5.Button1Click(Sender: TObject);

var
  json:ISuperObject;
  stream:TStringStream;

begin
  stream:=TStringStream.Create;
  parameters:=TStringList.Create;
  try
    cursor := crHourGlass;
    initConnection;
// return this: {"access_token":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAAAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","token_type":"bearer"}
    ringBear := getRingBear(requestRingBear);//the caller needs to free the stream
    initConnection;
    requestTwits;
    initConnection;
    logoff;//the caller needs to free the stream
  finally
    cursor := crDefault;
    memo1.Lines.Add('stream reposne' +stream.DataString);
    stream.Free;
    parameters.Free;
  end;
end;

function TForm5.getRingBear(input: TStringstream): string;
var
  json : ISuperObject;
begin
  json := TSuperObject.ParseStream(input,true);
  result := json.S['access_token'];
  input.Free;
end;

procedure TForm5.IdLogDebug1Receive(ASender: TIdConnectionIntercept;
  var ABuffer: TBytes);
var
  i: Integer;
  s: String;
begin
  s := '';

  for i := Low(ABuffer) to High(ABuffer) do
    s := s + chr(ABuffer[i]);

  Memo1.Lines.Add('Recived: '+s);
end;
procedure TForm5.IdLogDebug1Send(ASender: TIdConnectionIntercept;
  var ABuffer: TBytes);
var
  i: Integer;
  s: String;
begin
  s := '';

  for i := Low(ABuffer) to High(ABuffer) do
    s := s + chr(ABuffer[i]);

  Memo1.Lines.Add('SEND: '+s);
end;

end.

dfm 需要包含:

object Form5: TForm5
  Left = 0
  Top = 0
  Caption = 'Form5'
  ClientHeight = 546
  ClientWidth = 605
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  DesignSize = (
    605
    546)
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 288
    Top = 513
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Memo1: TMemo
    Left = 8
    Top = 8
    Width = 589
    Height = 499
    Anchors = [akLeft, akTop, akRight, akBottom]
    Lines.Strings = (
      'Memo1')
    ScrollBars = ssVertical
    TabOrder = 1
  end
  object IdHTTP1: TIdHTTP
    Intercept = IdLogDebug1
    IOHandler = IdSSLIOHandlerSocketOpenSSL1
    AllowCookies = True
    ProxyParams.BasicAuthentication = False
    ProxyParams.ProxyPort = 0
    Request.ContentLength = -1
    Request.Accept = 'text/html, */*'
    Request.BasicAuthentication = False
    Request.UserAgent = 'Mozilla/3.0 (compatible; Indy Library)'
    HTTPOptions = [hoForceEncodeParams]
    Left = 280
    Top = 136
  end
  object IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL
    Intercept = IdLogDebug1
    MaxLineAction = maException
    Port = 0
    DefaultPort = 0
    SSLOptions.Mode = sslmUnassigned
    SSLOptions.VerifyMode = []
    SSLOptions.VerifyDepth = 0
    Left = 296
    Top = 48
  end
  object IdLogDebug1: TIdLogDebug
    OnReceive = IdLogDebug1Receive
    OnSend = IdLogDebug1Send
    Left = 136
    Top = 192
  end
  object IdEncoderMIME1: TIdEncoderMIME
    FillChar = '='
    Left = 424
    Top = 256
  end
end

评论:

您必须在 Twitter 中注册应用程序。

你需要来自推特的密钥和秘密。

这是此处提到的应用程序 API 的应用程序, 使用 pin 码实现用户 oauth 是另一个复杂的数量级,并且需要用户活动来输入 pin 码。如果您需要有关该外观的更多信息,请在此处包含详细说明以及非常好的图表。那里的代码不完整,并且缺少dfm。Dropbox oauth 上有一个完整的例子,但我现在找不到。

delphi xe5中,有 delphi 附带的 oauth 客户端,它应该让你的生活更轻松。

注销不起作用。

并且 ringBear 是指巴尼·斯汀森在他的婚礼中的戒指熊,而不是戒指持有者,因为推特称它为熊(我认为来自信标同意,而不是婚礼)

这个想法很简单。请求 ringBear,然后请求 twits 然后注销。

于 2014-08-04T08:15:24.120 回答