kbmmw 做REST 服务签名认证的一种方式

Posted xalion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kbmmw 做REST 服务签名认证的一种方式相关的知识,希望对你有一定的参考价值。

一般对外提供提供REST 服务,由于信息安全的问题, 都要采用签名认证,今天简单说一下在KBMMW 中如何

实现简单的签名服务?

整个签名服务,模仿阿里大鱼的认证方式,大家可以根据实际情况自己修改。

没有太多的解释,直接上马

     [kbmMW_Rest(method:get, path:getwithcheck)]
     [kbmMW_Method]
     function getwithcheck(

          [kbmMW_Rest(value: "$p1", required: true)] const p1:string;

          [kbmMW_Rest(value: "$p2", required: true)] const p2:string;

          [kbmMW_Rest(value: "$p3", required: true)] const p3:string;

          [kbmMW_Rest(value: "$AccessKeyId", required: true)] const AccessKeyId:string;

          [kbmMW_Rest(value: "$Timestamp", required: true)] const  Timestamp:string;
          [kbmMW_Rest(value: "$Action", required: true)] const  Action:string;

          [kbmMW_Rest(value: "$Signature", required: true)] const Signature:string):string;

  end;



const

  AppSecret=sdjhidbTdlfdsj133edyeR;
  appkey=xaliontestok;


function MakeSign(const AParams: TStringList; const AppSecret: string): string;


implementation

uses kbmMWExceptions, mainp;

{$R *.dfm}
 function specialUrlEncode(const sStr:string):string;
  begin
// URLEncode后再增加三种字符替换:加号(+)替换成 %20、星号(*)替换成 %2A、%7E 替换回波浪号(~)


     Result :=TNetEncoding.URL.EncodeForm(sStr);
     Result.Replace(+,%20).Replace(*,%2A).Replace(%7E,~);
  end;

function MakeSign(const AParams: TStringList; const AppSecret: string): string;
  var
    I: Integer;
    sortedQueryString :string;
    stringToSign: string;
    sSign :string;
    outs:  TStringList;

    pn,pv:string;





    skey:Tbytes;
 begin

    outs:= AParams;
    outs.UseLocale:=True;
    outs.Sort;


    // 参数拼接
    sortedQueryString:= ‘‘;

    for I := 0 to outs.Count - 1 do
    begin

      pn:=specialUrlEncode(outs.Names[I]);

      pv:=specialUrlEncode(outs.Values[outs.Names[I]]);

      sortedQueryString:= sortedQueryString +pn + =+ pv+&;


    end;
    setlength(sortedQueryString,length(sortedQueryString)-1);

    stringToSign :=GET&%2F& +  specialUrlEncode(sortedQueryString);

    skey:=THashSHA1.GetHMACAsBytes(Tencoding.UTF8.GetBytes(stringToSign), Tencoding.UTF8.GetBytes(AppSecret+&));


     sSign := TBase64Encoding.Create.EncodeBytesToString(skey);
     Result :=specialUrlEncode(sSign);

  end;

function TkbmMWCustomHTTPSmartService1.getwithcheck(const p1, p2, p3,
  AccessKeyId, Timestamp, Action, Signature: string): string;
var

   inputp:Tstringlist;

   inputsign:string;

begin

   inputp:=Tstringlist.Create;

   inputp.Values[P1]:=p1;
   inputp.Values[P2]:=p2;
   inputp.Values[P3]:=p3;

   inputp.Values[AccessKeyId]:=AccessKeyId;
   inputp.Values[Timestamp]:=Timestamp;
   inputp.Values[Action]:=Action;
  // inputp.Values[‘Signature‘]=Signature;



   inputsign:= MakeSign(inputp,AppSecret);

   if inputsign<>specialUrlEncode(Signature) then
     begin
       Result:={result:{"ok":"error","value":"sign error"}};
       exit;
     end;

   if appkey<>AccessKeyId then
     begin
        Result:={result:{"ok":"error","value":"can not find appkey"}};
       exit;
     end;


     Result:={"result":{"ok":"ok","value":"+Action+"}};;


end;

 

客户端也很简单

function TForm1.SendSMS(const AppKey, AppSecret, ReceiveNumber, FreeSignName,
  TemplateCode, TemplateContent: string; var ResultMsg: string): Boolean;




  function specialUrlEncode(const sStr:string):string;
  begin
// URLEncode后再增加三种字符替换:加号(+)替换成 %20、星号(*)替换成 %2A、%7E 替换回波浪号(~)


     Result :=TNetEncoding.URL.EncodeForm(sStr);
     Result.Replace(+,%20).Replace(*,%2A).Replace(%7E,~);
  end;


  function MakeSign(const AParams: TStringList; const AppSecret: string;var sortQueryStringTmp :String): string;
  var
    I: Integer;
    sortedQueryString :string;
    stringToSign: string;
    sSign :string;
    outs:  TStringList;

    pn,pv:string;

    skey:Tbytes;
 begin

    outs:= AParams;
    outs.UseLocale:=True;
    outs.Sort;

    //SortString( AParams,outs);

    // 参数拼接
    sortQueryStringTmp := ‘‘;

    for I := 0 to outs.Count - 1 do
    begin

      pn:=specialUrlEncode(outs.Names[I]);

      pv:=specialUrlEncode(outs.Values[outs.Names[I]]);

      sortQueryStringTmp := sortQueryStringTmp +pn + =+ pv+&;


    end;
   setlength(sortQueryStringTmp,length(sortQueryStringTmp)-1);
    sortedQueryString:=sortQueryStringTmp;

    stringToSign :=GET&%2F& +  specialUrlEncode(sortedQueryString);



    skey:=THashSHA1.GetHMACAsBytes(Tencoding.UTF8.GetBytes(stringToSign), Tencoding.UTF8.GetBytes(AppSecret+&));


     sSign := TBase64Encoding.Create.EncodeBytesToString(skey);
     Result :=specialUrlEncode(sSign);




  end;

var
  HTTP: TNetHTTPClient;
  JO: TJSONObject;
  Params: TStringList;
  Response: string;
  code:TGUID;
  sortQueryStringTmp :string;
  signature :string;
  sURL :string;

  ResponseStr: TStringStream;




begin
  Result := False;

  CreateGUID(code);
  HTTP := TNetHTTPClient.Create(nil);
  Params := TStringList.Create();
  ResponseStr :=TStringStream.Create(‘‘, TEncoding.ASCII);//中文用UTF8
  try
//;
//
//请求参数中不允许出现以Signature为key的参数。参考代码如下```
//String accessKeyId = “testId”;String accessSecret = “testSecret”;
//java.text.SimpleDateFormat df = new java.text.SimpleDateFormat(“yyyy-MM-dd’T’HH:mm:ss’Z’”);
//df.setTimeZone(new java.util.SimpleTimeZone(0, “GMT”));// 这里一定要设置GMT时区
//
//java.util.Map paras = new java.util.HashMap();
//// 1. 系统参数
//paras.put(“SignatureMethod”, “HMAC-SHA1”);
//paras.put(“SignatureNonce”, java.util.UUID.randomUUID().toString());
//paras.put(“AccessKeyId”, accessKeyId);
//paras.put(“SignatureVersion”, “1.0”);
//paras.put(“Timestamp”, df.format(new java.util.Date()));
//paras.put(“Format”, “XML”);
//
//// 2. 业务API参数
//paras.put(“Action”, “SendSms”);
//paras.put(“Version”, “2017-05-25”);
//paras.put(“RegionId”, “cn-hangzhou”);
//paras.put(“PhoneNumbers”, “15300000001”);
//paras.put(“SignName”, “阿里云短信测试专用”);
//paras.put(“TemplateParam”, “{”customer”:”test”}”);
//paras.put(“TemplateCode”, “SMS_71390007”);
//paras.put(“OutId”, “123”);

    Params.Values[P2] := HMAC-SHA1;
    Params.Values[P3] := GUIDToString(code);
    Params.Values[AccessKeyId] := AppKey;
    Params.Values[P1] := 1.0;
//    Params.Values[‘Timestamp‘] := FormatDateTime(‘yyyy-mm-dd hh:mm:ss‘,  now - 1/3);
    Params.Values[Timestamp] := FormatDateTime(yyyy-MM-dd‘‘T‘‘HH:mm:ss‘‘Z‘‘, now-1/3);
   // Params.Values[‘Format‘] := ‘JSON‘;
    Params.Values[Action] := SendSms;
   // Params.Values[‘Version‘] := ‘2017-05-25‘;
   // Params.Values[‘RegionId‘] := ‘cn-hangzhou‘;
    //Params.Values[‘PhoneNumbers‘] := ReceiveNumber;


   // Params.Values[‘SignName‘] := FreeSignName;


   // Params.Values[‘TemplateParam‘] := TemplateContent;
   // Params.Values[‘TemplateCode‘] := TemplateCode;

    signature:=MakeSign(Params,AppSecret,sortQueryStringTmp);



    sURL := http://127.0.0.1/xalionrest/getwithcheck?signature=+signature+&+sortQueryStringTmp;
     Memo1.Lines.Text :=sURL;

    try

     resultmsg:=http.Get(sURL).ContentAsString ;

     Memo2.Lines.add( resultmsg);


    except
      on E: Exception do
      begin
        ResultMsg := E.Message;
        Exit;
      end;
    end;

   finally
    HTTP.Free;
    Params.Free;
    ResponseStr.Free;
  end;

end;

运行结果,有图有真相

 技术分享图片

打完收工。

 

以上是关于kbmmw 做REST 服务签名认证的一种方式的主要内容,如果未能解决你的问题,请参考以下文章

使用kbmmw 的REST 服务实现上传大文件

使用nginx 做kbmmw REST 服务的负载均衡

REST easy with kbmMW #15 – Handling HTTP POST

REST easy with kbmMW #4 – Access management

REST API 的安全认证,从 OAuth 2.0 到 JWT 令牌

REST easy with kbmMW #20 – OpenAPI and Swagger UI