unit JITAuth; interface uses xmldom, XMLIntf, msxmldom, XMLDoc, Classes, SysUtils, Dialogs, LoggerImport, mybean.core.objects, InterfaceCA, IdHTTP, Forms; type SHeadInfo = Record Version:String; ServiceType:String; AuthResult:String; ErrorCode:String; ErrorDesc:String; end; SBodyInfo = Record AuthMode:String; AuthResult:String; AccessControlResult:String; AttrList:TStringList; end; TJITAuth = class(TMyBeanInterfacedObject, ICAClient) private function RandomNum: string; function GetNodeAttributeValue(xmlNode:IXMLNode; strAttribute:String):String; procedure ParseHeadNode(HeadNode:IXMLNode; var HeadInfo: SHeadInfo); procedure ParseRootNode(RootNode:IXMLNode; var HeadInfo:SHeadInfo; var BodyInfo:SBodyInfo); procedure ParseBodyNode(BodyNode:IXMLNode; var BodyInfo: SBodyInfo); function GenRandom: String; procedure InitRequestHead(AIdHttp: TIdHttp); function RequestUserJsonBySubjectDN(ASubjectDN: string): string; public function Request: string; stdcall; end; implementation uses JITComVCTKLib_TLB, CAImport, Windows, StrUtils, AppCentreImport, InterfaceAppCentre; function SplitString(const Source, Ch:string): TStringList; var Temp: string; iLoop: Integer; begin Result := TStringList.Create; Temp := Source; iLoop := Pos(Ch, Source); while iLoop <> 0 do begin Result.Add(copy(temp, 0, iLoop-1)); Delete(temp, 1, iLoop); iLoop := Pos(Ch, Temp); end; Result.Add(temp); end; { TJITAuth } function TJITAuth.RandomNum: string; const CHS: string = '1234567890abcdefghijklmnopqrstopqrstuvwxyz'; ASIZE: Integer = 6; var iLoop: Integer; key: array[0..5] of char; begin Randomize; for iLoop := 0 to ASIZE - 1 do key[iLoop] := CHS[Random(36)]; Result := string(key); end; procedure TJITAuth.InitRequestHead(AIdHttp: TIdHttp); begin AIdHttp.Request.Accept := 'text/html, */*'; AIdHttp.Request.ContentType := 'text/xml'; AIdHttp.AllowCookies := True; AIdHttp.ProxyParams.BasicAuthentication := False; AIdHttp.ProxyParams.ProxyPort := 0; AIdHttp.Request.ContentLength := -1; AIdHttp.Request.ContentRangeEnd := 0; AIdHttp.Request.ContentRangeStart := 0; AIdHttp.Request.ContentType := 'text/xml'; AIdHttp.Request.Accept := 'text/html, */*'; AIdHttp.Request.BasicAuthentication := False; AIdHttp.HTTPOptions := [hoForceEncodeParams]; end; function TJITAuth.GenRandom: String; var ReponseData, HostAddr, PostMsg:String; StrStream:TStringStream; RootNode:IXMLNode; ChildNodes, BodyChildNode:IXMLNodeList; BodyNode, TempNode:IXMLNode; I,J:Integer; PostStream:TStringStream; AConfig: ICAConfig; AIdHttp: TIdHttp; AXMLDoc: TXMLDocument; begin AConfig := GetCAConfig; Result:= ''; PostMsg := '' + '' + '' + '1.0' + 'OriginalService' + '' + '' + '' + AConfig.GetAppID + '' + '' + ''; PostStream:=TStringStream.Create(AnsiToUtf8(PostMsg)); HostAddr := AConfig.GetURL; AIdHttp := TIdHTTP.Create(nil); InitRequestHead(AIdHttp); try ReponseData:= AIdHttp.Post(AConfig.GetURL, PostStream); except on Ex: Exception do begin ShowMessage('CA服务器可能不存在,详细错误:' + Ex.Message); FreeAndNil(AIdHttp); PostStream.Free; Exit; end; end; PostStream.Free; FreeAndNil(AIdHttp); StrStream:=TStringStream.Create(ReponseData); AXMLDoc := TXMLDocument.Create(Application); AXMLDoc.Active := True; try AXMLDoc.LoadFromStream(StrStream); RootNode := AXMLDoc.DocumentElement; ChildNodes:=RootNode.ChildNodes; for i:=0 to ChildNodes.Count -1 do begin BodyNode := ChildNodes.Get(i); if UpperCase(BodyNode.NodeName) ='BODY' then begin BodyChildNode:=BodyNode.ChildNodes; if BodyChildNode.Count<>1 then begin EXIT; end; TempNode := BodyChildNode.Get(0); Result:= TempNode.NodeValue; end; end; except on Ex: Exception do begin ShowMessage('CA返回结果解析异常:'+ Ex.Message); StrStream.Free; AXMLDoc.Free; Exit; end; end; StrStream.Free; AXMLDoc.Free; end; function TJITAuth.Request: string; var JITVCTKObj:IJITVCTK; StrRandom, StrSignData:String; lErrorCode:Integer; ReponseData:String; StrStream:TStringStream; PostStream:TStringStream; RootNode:IXMLNode; HeadInfo:SHeadInfo; BodyInfo:SBodyInfo; I, iLoop:Integer; AConfig: ICAConfig; AIdHttp: TIdHTTP; AXMLDoc: TXMLDocument; begin ////////////////////////////////////////////////////////////////////////// // 1. 生成认证请求报文 ////////////////////////////////////////////////////////////////////////// AConfig := GetCAConfig; JITVCTKObj:=CoJITVCTK.Create; lErrorCode:=JITVCTKObj.SetCert('SC', '', '', '', AConfig.GetCaSubject, ''); if lErrorCode <> 0 then Exit; StrRandom := GenRandom; if StrRandom='' then Exit; StrSignData:=JITVCTKObj.AttachSignStr('', StrRandom); if StrSignData = '' then Exit; PostStream:=TStringStream.Create(''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString('1.1'); PostStream.WriteString('AuthenService'); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''+ '192.168.1.100' +''); PostStream.WriteString(''); PostStream.WriteString('' + AConfig.GetAppID + ''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString('' + StrSignData + ''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString('true'); PostStream.WriteString(''); PostStream.WriteString(''); { PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); } PostStream.WriteString(''); PostStream.WriteString(''); PostStream.WriteString(''); ////////////////////////////////////////////////////////////////////////// // 2. 发送认证请求报文 ////////////////////////////////////////////////////////////////////////// AIdHttp := TIdHTTP.Create(nil); InitRequestHead(AIdHttp); PostStream.Position := 0; try ReponseData := AIdHttp.Post(AConfig.GetURL, PostStream); except on Ex: Exception do begin ShowMessage('CA服务器可能不存在,详细错误:' + Ex.Message); FreeAndNil(AIdHttp); PostStream.Free; Exit; end; end; PostStream.Free; FreeAndNil(AIdHttp); ///////////////////////////////////////////////////////////////////////// // 3. 解析服务器响应报文 ////////////////////////////////////////////////////////////////////////// StrStream:=TStringStream.Create(ReponseData); AXMLDoc := TXMLDocument.Create(Application); try AXMLDoc.LoadFromStream(StrStream); RootNode := AXMLDoc.DocumentElement; ParseRootNode(RootNode, HeadInfo, BodyInfo); except on Ex: Exception do begin ShowMessage('CA返回结果解析异常:'+ Ex.Message); StrStream.Free; AXMLDoc.Free; Exit; end; end; StrStream.Free; AXMLDoc.Free; Debug('版本:'+ HeadInfo.Version, 'TJITAuth.Request'); Debug('服务类型:' + HeadInfo.ServiceType, 'TJITAuth.Request'); Debug('认证结果:' + HeadInfo.AuthResult, 'TJITAuth.Request'); Debug('错误码:' + HeadInfo.ErrorCode, 'TJITAuth.Request'); Debug('错误信息:' + HeadInfo.ErrorDesc, 'TJITAuth.Request'); Debug('认证模式:' + BodyInfo.AuthMode, 'TJITAuth.Request'); Debug('认证结果:' + BodyInfo.AuthResult, 'TJITAuth.Request'); Debug('访问控制:' + BodyInfo.AccessControlResult, 'TJITAuth.Request'); if BodyInfo.AttrList <> nil then begin try for iLoop := 0 to BodyInfo.AttrList.Count - 1 do if SameText('X509Certificate.SubjectDN', BodyInfo.AttrList[iLoop]) then begin Result := RequestUserJsonBySubjectDN(BodyInfo.AttrList[iLoop + 2]); Break; end; finally BodyInfo.AttrList.Free; end; end; end; function TJITAuth.RequestUserJsonBySubjectDN(ASubjectDN: string): string; const GETUSER_URL: string = 'http://%s:%d/api/basic/GetUserByCA?appKey=%s&appSecret=%s&ca=%s'; var AItems: TStrings; iLoop, jLoop: Integer; strTmp: string; AID: string; AIdHttp: TIdHttp; AppCentreConfig: IAppCentreConfig; AURL: string; begin AItems := SplitString(ASubjectDN, ','); try for iLoop := 0 to AItems.Count - 1 do begin strTmp := Trim(AItems[iLoop]); if Pos('T=', strTmp) = 1 then begin AID := Copy(StrTmp, 3, Length(StrTmp) - 2); Break; end; end; finally FreeAndNil(AItems); end; if AID = '' then Exit; AIdHttp := TIdHttp.Create(Application); try AppCentreConfig := GetAppCentreConfig; AURL := Format(GETUSER_URL, [Utf8ToAnsi(AppCentreConfig.GetIP), AppCentreConfig.GetPort, AppCentreConfig.GetLxtAppKey, AppCentreConfig.GetLxtAppSecret, AID]); Result := Utf8ToAnsi(AIdHttp.Get(AURL)); finally FreeAndNil(AIdHttp); end; end; function TJITAuth.GetNodeAttributeValue(xmlNode:IXMLNode; strAttribute:String):String; begin // xmlNode.Get end; procedure TJITAuth.ParseHeadNode(HeadNode:IXMLNode; var HeadInfo: SHeadInfo); var ChildNodes:IXMLNodeList; ChildNode:IXMLNode; I:Integer; tempValue:String; begin ChildNodes:=HeadNode.GetChildNodes(); for I:=0 to ChildNodes.Count-1 do begin ChildNode:=ChildNodes.Get(i); tempValue:=ChildNode.Text; if lowercase(ChildNode.NodeName)='version' then begin HeadInfo.Version := tempValue; end else if lowercase(ChildNode.NodeName)='servicetype' then begin HeadInfo.ServiceType := tempValue; end else if lowercase(ChildNode.NodeName)='messagestate' then begin HeadInfo.AuthResult := tempValue; end else if lowercase(ChildNode.NodeName)='messagecode' then begin HeadInfo.ErrorCode := tempValue; end else if lowercase(ChildNode.NodeName)='messagedesc' then begin HeadInfo.ErrorDesc := tempValue; end; end; end; procedure TJITAuth.ParseRootNode(RootNode:IXMLNode; var HeadInfo:SHeadInfo; var BodyInfo:SBodyInfo); var ChildNodes:IXMLNodeList; ChildNode:IXMLNode; I:Integer; begin ChildNodes:=RootNode.GetChildNodes(); for I:=0 to ChildNodes.Count-1 do begin ChildNode:=ChildNodes.Get(I); if UpperCase(ChildNode.NodeName)='HEAD' then begin ParseHeadNode(ChildNode, HeadInfo); end else if UpperCase(ChildNode.NodeName)='BODY' then begin ParseBodyNode(ChildNode, BodyInfo); end; end; end; procedure TJITAuth.ParseBodyNode(BodyNode:IXMLNode; var BodyInfo: SBodyInfo); var ChildNodes:IXMLNodeList; ChildNode, AttribChildNode:IXMLNode; I,J:Integer; AuthChildNodes:IXMLNodeList; AttrName, AttrNameSpace, AttrValue:String; begin ChildNodes:=BodyNode.GetChildNodes(); for I:=0 to ChildNodes.Count-1 do begin ChildNode:=ChildNodes.Get(I); if lowercase(ChildNode.NodeName)='authresultset' then begin AuthChildNodes:=ChildNode.ChildNodes; for J:=0 to AuthChildNodes.Count-1 do begin AttribChildNode:=AuthChildNodes.Get(J); if lowercase(AttribChildNode.NodeName)='authresult' then begin if AttribChildNode.HasAttribute('authMode') then BodyInfo.AuthMode:=AttribChildNode.Attributes['authMode']; if AttribChildNode.HasAttribute('success') then BodyInfo.AuthResult:=AttribChildNode.Attributes['success']; end; end; end else if lowercase(ChildNode.NodeName)='accesscontrolresult' then begin BodyInfo.AccessControlResult:=ChildNode.Text; end else if lowercase(ChildNode.NodeName)='attributes' then begin AuthChildNodes:=ChildNode.ChildNodes; BodyInfo.AttrList:=TStringList.Create; for J:=0 to AuthChildNodes.Count-1 do begin AttribChildNode:=AuthChildNodes.Get(J); if lowercase(AttribChildNode.NodeName)='attr' then begin if AttribChildNode.HasAttribute('name') then AttrName:=AttribChildNode.Attributes['name']; if AttribChildNode.HasAttribute('namespace') then AttrNameSpace:=AttribChildNode.Attributes['namespace']; AttrValue:=AttribChildNode.NodeValue; BodyInfo.AttrList.Add(AttrName); BodyInfo.AttrList.Add(AttrNameSpace); BodyInfo.AttrList.Add(AttrValue); end; end; end; end; end; end.