WCF服务使用wsHttpBinding-操作HTTP请求标头但是,本教程提到使用basicHttpBinding,这是不可接受的-我需要wsHttpBinding。这个想法是在WCF服务上有一个自定义的BasicAuthenticationModule,它将从HTTP请求中读取“Authorization”标头,并根据“Authorization”标头内容执行身份验证过程。问题是缺少“授权”标头!我已经实现了具有自定义行为的IClientMessageInspector,以便操作传出消息并添加自定义SOAP标头。我在BeforeSendRequest函数中添加了以下代码:HttpRequestMessagePropertyhttpRequest=request.Properties.Where(x=>x.Key=="httpRequest").Single().Value;httpRequest.Headers.Add("CustomHeader","CustomValue");这应该有效,并且根据许多网络资源,它适用于basicHttpBinding但不适用于wsHttpBinding。当我说“工作”时,我的意思是WCF服务成功接收了标头。下面是在WCF服务器端检查传入HTTP消息的简化函数:publicvoidOnAuthenticateRequest(objectsource,EventArgseventArgs){//如果存在,则检查授权标头stringauthHeader=app.Request.Headers["Authorization"];如果(string.IsNullOrEmpty(authHeader)){app.Response.StatusCode=401;app.Response.End();}}2011年9月这篇文章的底部说使用wsHttpBinding是不可能的。我不想接受那个回应。作为旁注,如果我在IIS中使用内置的基本身份验证模块而不是自定义模块,我会得到Theparameter'username'mustnotcontaincommas。**尝试Roles.IsInRole("RoleName")或`[PrincipalPermission(SecurityAction.Demand,Role="RoleName")]时的错误消息可能是因为我的PrimaryIdentity.Name属性包含证书PrimaryIdentity.Name名称,因为我正在使用TransportWithMessageCredential安全与基于证书的消息安全。我愿意接受建议以及解决问题的替代方法。谢谢。更新似乎稍后在整个WCF服务代码中正确读取了HTTP标头。(HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties["httpRequest"]包含我的自定义标头。但是,这已经是消息级别的了。如何将标头传递给传输身份验证例程?更新2经过一番研究,我得出的结论是,当Web浏览器收到401的HTTP状态代码时,它会显示一个登录对话框,我可以在其中指定我的凭据。但是,WCF客户端只是抛出异常并且不想发送凭据。在InternetExplorer中访问https://myserver/myservice/service.svc时,我能够验证此行为。尝试使用此链接中的信息进行修复,但无济于事。这是WCF中的错误还是我遗漏了什么?编辑下面是我的system.servicemodel的相关部分(来自web.config)——我很确定我已经正确配置了它。.....................服务返回的异常为:HTTP请求未经授权,客户端认证方案为“Anonymous”。从服务器收到的身份验证标头是“BasicRealm,Negotiate,NTLM”。(远程服务器返回错误:(401)Unauthorized。)有趣的是,当我对上面的答案写最后一条评论时,我停顿了一下。我的评论包含“...如果HTTP标头不包含“授权”标头,我将状态设置为401,这会导致异常。”我将状态设置为401。有什么想法吗?解决方案一直存在。即使我明确添加它,初始数据包也不包含授权标头。但是,正如我在授权模块处于非活动状态时所测试的那样,每个后续数据包都包含它。所以我想,为什么我不尝试将这个初始数据包与其他数据包区分开来呢?因此,如果我看到它是初始数据包,请将HTTP状态代码设置为200(OK),如果不是,请检查身份验证标头。这很简单,因为初始数据包在SOAP信封中发送对安全令牌(包含令牌)的请求。好的,让我们看看我的实现,以防其他人需要它。这是BasicAuthenticationModule实现,它实现了IHTTPModule:application.EndRequest+=newEventHandler(this.OnEndRequest);}publicvoidOnAuthenticateRequest(objectsource,EventArgseventArgs){HttpApplicationapp=(HttpApplication)source;//获取请求流StreamhttpStream=app.Request.InputStream;//我将流转换为字符串,这样我就可以搜索已知的子字符串byte[]byteStream=newbyte[httpStream.Length];httpStream.Read(byteStream,0,(int)httpStream.Length);字符串strRequest=Encoding.ASCII.GetString(byteStream);//这是初始SOAP信封的结尾//不确定这是否是最快的方法,但工作正常intidx=strRequest.IndexOf("",0);httpStream.Seek(0,SeekOrigin.Begin);if(idx!=-1){//初始数据包f结束,什么都不做(HTTP状态码设置为200)返回;}//如果存在则检查授权标头stringauthHeader=app.Request.Headers["Authorization"];if(!string.IsNullOrEmpty(authHeader)){if(authHeader==null||authHeader.Length==0){//没有凭据;匿名请求返回;}authHeader=authHeader.Trim();if(authHeader.IndexOf("Basic",0)!=0){//标头不包含基本授权令牌//我们将传递它并//假设其他人会处理它return;}stringencodedCredentials=authHeader.Substring(6);byte[]decodedBytes=Convert.FromBase64String(encodedCredentials);字符串s=newASCIIEncoding().GetString(decodedBytes);string[]userPass=s.Split(newchar[]{':'});字符串用户名=userPass[0];字符串密码=用户密码[1];//用户根据SqlMemberShipProvider进行验证//如果通过验证,则从角色提供者和通用原则中检索角色al被创建//通用主体被分配给应用程序的用户上下文//if(Membership.ValidateUser(username,password)){string[]roles=Roles.GetRolesForUser(username);app.Context.User=newGenericPrincipal(newGenericIdentity(username,"MembershipProvider"),角色);}else{拒绝访问(应用程序);返回;}}else{app.Response.StatusCode=401;app.Response.End();}}publicvoidOnEndRequest(objectsource,EventArgseventArgs){//授权标头不存在。//响应状态设置为401AccessDenied。//我们现在将预期的授权方法添加//到响应标头,因此客户端知道//它需要发送凭据来进行身份验证if(HttpContext.Current.Response.StatusCode==401){HttpContextcontext=HttpContext.Current;context.Response.AddHeader("WWW-Authenticate","BasicRealm");}}privatevoidDenyAccess(HttpApplicationapp){app.Response.StatusCode=403;app.Response.StatusDescription="禁止";//也写入响应流,给用户//错误的视觉指示app.Response.Write("403Forbidden");app.CompleteRequest();}}重要说明:为了使我们能够读取http请求流,必须不启用ASP.NETCompatibility对于IIS加载此模块,必须将其添加到web.config的部分,如下所示:但在此之前,您必须确保BasicAuthenticationModule部分未锁定,默认情况下应锁定。如果锁定,则无法更换。解锁模块:(注意:我使用的是IIS7.5)打开IIS管理器在左窗格中,单击您的主机名在中间窗格的“管理”部分下,打开“配置编辑器”单击上方的组合框在窗格部分的“Section”标签旁边,展开“system.webServer”并导航到“modules”在“(collections)”键下,单击“(Count=nn)”值,将出现一个窗口,其中包含“……”小按钮。点击它。在“项目”列表中,找到“BasicAuthenticationModule”并单击右侧窗格中的“解锁项目”(如果存在!)。如果您更改了此设置,请关闭配置编辑器以保存更改。在客户端,您需要能够将自定义HTTP标头添加到传出消息中。执行此操作的最佳方法是实现IClientMessageInspector并使用BeforeSendRequest函数添加标头。我不会解释IClientMessageInspector是如何实现的,网上有很多关于这个主题的资源。要在消息中添加“授权”HTTP标头,请执行以下操作:如果(request.Properties.ContainsKey(HttpRequestMessageProperty.Name)){httpRequestMessageProperty=request.Properties[HttpRequestMessageProperty.Name]asHttpRequestMessageProperty;如果(httpRequestMessageProperty==null){httpRequestMessageProperty=newHttpRequestMessageProperty();request.Properties.Add(HttpRequestMessageProperty.Name,httpRequestMessageProperty);}}else{httpRequestMessageProperty=newHttpRequestMessageProperty();request.Properties.Add(HttpRequestMessageProperty.Name,httpRequestMessageProperty);}//将授权标头添加到WCF请求httpRequestMessageProperty.Headers.Add("Authorization","Basic"+Convert.ToBase64String(Encoding.ASCII.GetBytes(Service.Proxy.ClientCredentials.UserName.UserName+":"+Service.Proxy.ClientCredentials.UserName.Password)));返回空值;你走了,这需要一段时间才能弄清楚,但这是值得的,因为我在网上发现了很多类似的未回答的问题你正在尝试实现HTTP身份验证,所以请查看这篇MSDN文章以确保您已正确配置服务。如您所知,您引用的教程适用于basicHttpBinding,但wsHttpBinding需要特殊配置才能支持HTTP身份验证。以上就是C#学习教程:WCF服务使用wsHttpBinding-操作HTTP请求头分享全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文来自网络收集,不代表作品如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
