http json token
https使用证书来保证链接的安全,是目前最为流行的做法。
另一种保证HTTP 函数的安全,就是http json token,只有TOKEN验证通过,才能调用方法(一般指通过HTTP GET/POST调用的REST API)。
1)客户端调用REST API的时候,要增加TOKEN参数及值
演示使用HS256,只有公钥,没有私钥
procedure TForm1.Button5Click(Sender: TObject);//HTTP TOKENbegin const secret: string = 'ynMiddleWare(cross)'; //公钥 var LToken: TJWT := TJWT.Create; LToken.Claims.Subject := secret; //主题 LToken.Claims.IssuedAt := Now; //签发时间 LToken.Claims.Expiration := Now + 1; //超时 LToken.Claims.Issuer := secret; //签发人 var LAlg: TJOSEAlgorithmId := TJOSEAlgorithmId.HS256; //hs256 var s: string := TJOSE.SerializeCompact(secret, LAlg, LToken); var url: string := 'http://192.168.1.5:1122/restquerytoken?accountno=1&token=' + s + '&sql=' + TNetEncoding.URL.Encode('select * from tunit'); s := IdHTTP1.Get(url); Memo1.Lines.Add(s); LToken.Free;end;
2)服务端处理
服务端验证TOKEN的时候,主题、超时、签发人。。。这些都是验证可选项,最简验证:可以只验证密钥。
当然,验证的项越多,越安全。验证TOKEN不通过,不会执行函数的。
function VerifyToken(const request: string): string;begin const secret: string = 'ynMiddleWare(cross)'; //公钥 var LToken: TJWT := TJOSE.Verify(secret, ParamValue(request, 'token')); if LToken.Verified then begin //主题、超时。。。等项,都是可选验证项,验证项越多,越安全// if LToken.Claims.Subject <> '主题' then //主题// begin// Result := '{"return":"false","error":"Subject error"}';// exit;// end;// if LToken.Claims.Expiration < Now then //超时// begin// Result := '{"return":"false","error":"Expiration time passed"}';// Exit;// end;// if LToken.Claims.Issuer <> '签发人' then //签发人// begin// Result := '{"return":"false","error":"Issuer error"}';// Exit;// end; Result := '{"return":"true"}'; end else Result := '{"return":"false","error":"Verify error"}'; LToken.Free;end;
FHttpServer.Get('/restquerytoken', procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse) begin var s: string := VerifyToken(ARequest.RawPathAndParams); //验证token if sametext('{"return":"true"}', s) then //验证通过 begin var Pool: TUnidacPool := GetDBPool(ParamValue(ARequest.RawPathAndParams, 'accountno')); var dm: TUnidac := Pool.lock; AResponse.send(dm.RestQuery(ARequest.RawPathAndParams)); Pool.unlock(dm); end else AResponse.send(s); //返回错误信息 end);