你的位置:首页 > ASP.net教程

[ASP.net教程]DotNetOpenAuth实践之WCF资源服务器配置


上一篇我们写了一个OAuth2的认证服务器,我们也获取到access_token,那么这个token怎么使用呢,我们现在就来揭开

一般获取access_token用处就是访问接口资源,不然也用不到怎么大费周章的还要获取个token再去访问资源

而接口有几类:

WCF服务接口,WebApi,还有自己用如ashx,aspx写的接口提供给前端调用的接口

其中WCF接口DotNetOpenAuth.Sample例子中已经做了

这些接口公开对外就需要一个认证的过程才能访问(当然内部或者内网使用的也不用这么麻烦,毕竟认证也是影响性能的)

废话不多说,我们下面开始搭建资源服务器

首先,搭建WCF服务接口的资源认证

一、创建WCF资源服务器项目

2、添加DotNetOpenAuth到项目中

3、添加WCF服务,为了方便,我们添加支持ajax的wcf服务

 

4、重写ServiceAuthorizationManager

 1 using System; 2 using System.Collections.Generic; 3 using System.IdentityModel.Policy; 4 using System.Linq; 5 using System.Net.Http; 6 using System.Security.Cryptography; 7 using System.Security.Principal; 8 using System.ServiceModel; 9 using System.ServiceModel.Channels; 10 using System.ServiceModel.Security; 11 using System.ServiceModel.Web; 12 using System.Threading; 13 using System.Threading.Tasks; 14 using System.Web; 15 using DotNetOpenAuth.Messaging; 16 using DotNetOpenAuth.OAuth2; 17 using ProtocolException = System.ServiceModel.ProtocolException; 18  19 namespace WCFRescourcesServer.Code 20 { 21   public class IdefavAuthorizationManager : ServiceAuthorizationManager 22   { 23     public IdefavAuthorizationManager() 24     { 25     } 26  27     protected override bool CheckAccessCore(OperationContext operationContext) 28     { 29       if (!base.CheckAccessCore(operationContext)) 30       { 31         return false; 32       } 33  34       var httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; 35       var requestUri = operationContext.RequestContext.RequestMessage.Properties.Via; 36  37       return Task.Run(async delegate 38       { 39         ProtocolFaultResponseException exception = null; 40         try 41         { 42           var principal = await VerifyOAuth2Async( 43             httpDetails, 44             requestUri, 45             operationContext.IncomingMessageHeaders.Action ?? operationContext.IncomingMessageHeaders.To.AbsolutePath); 46           if (principal != null) 47           { 48             var policy = new OAuthPrincipalAuthorizationPolicy(principal); 49             var policies = new List<IAuthorizationPolicy> { policy }; 50  51             var securityContext = new ServiceSecurityContext(policies.AsReadOnly()); 52             if (operationContext.IncomingMessageProperties.Security != null) 53             { 54               operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext; 55             } 56             else 57             { 58               operationContext.IncomingMessageProperties.Security = new SecurityMessageProperty 59               { 60                 ServiceSecurityContext = securityContext, 61               }; 62             } 63  64             securityContext.AuthorizationContext.Properties["Identities"] = new List<IIdentity> { principal.Identity, }; 65  66             return true; 67           } 68           else 69           { 70             return false; 71           } 72         } 73         catch (ProtocolFaultResponseException ex) 74         { 75  76           exception = ex; 77         } 78         catch (ProtocolException ex) 79         { 80  81         } 82  83         if (exception != null) 84         { 85            86           // Return the appropriate unauthorized response to the client. 87           var outgoingResponse = await exception.CreateErrorResponseAsync(CancellationToken.None); 88           if (WebOperationContext.Current != null) 89             this.Respond(WebOperationContext.Current.OutgoingResponse, outgoingResponse); 90         } 91  92         return false; 93       }).GetAwaiter().GetResult(); 94     } 95  96     private static async Task<IPrincipal> VerifyOAuth2Async(HttpRequestMessageProperty httpDetails, Uri requestUri, params string[] requiredScopes) 97     { 98       var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer((RSACryptoServiceProvider)Common.Configuration.SigningCertificate.PublicKey.Key, (RSACryptoServiceProvider)Common.Configuration.EncryptionCertificate.PrivateKey)); 99       return await resourceServer.GetPrincipalAsync(httpDetails, requestUri, requiredScopes: requiredScopes);100     }101 102     private void Respond(OutgoingWebResponseContext responseContext, HttpResponseMessage responseMessage)103     {104       responseContext.StatusCode = responseMessage.StatusCode;105       responseContext.SuppressEntityBody = true;106       foreach (var header in responseMessage.Headers)107       {108         responseContext.Headers[header.Key] = header.Value.First();109       }110     }111   }112 }

5、实现OAuthPrincipalAuthorizationPolicy接口

 1 namespace OAuthResourceServer.Code { 2   using System; 3   using System.Collections.Generic; 4   using System.IdentityModel.Claims; 5   using System.IdentityModel.Policy; 6   using System.Linq; 7   using System.Security.Principal; 8   using System.Web; 9 10   public class OAuthPrincipalAuthorizationPolicy : IAuthorizationPolicy {11     private readonly Guid uniqueId = Guid.NewGuid();12     private readonly IPrincipal principal;13 14     /// <summary>15     /// Initializes a new instance of the <see cref="OAuthPrincipalAuthorizationPolicy"/> class.16     /// </summary>17     /// <param name="principal">The principal.</param>18     public OAuthPrincipalAuthorizationPolicy(IPrincipal principal) {19       this.principal = principal;20     }21 22     #region IAuthorizationComponent Members23 24     /// <summary>25     /// Gets a unique ID for this instance.26     /// </summary>27     public string Id {28       get { return this.uniqueId.ToString(); }29     }30 31     #endregion32 33     #region IAuthorizationPolicy Members34 35     public ClaimSet Issuer {36       get { return ClaimSet.System; }37     }38 39     public bool Evaluate(EvaluationContext evaluationContext, ref object state) {40       evaluationContext.AddClaimSet(this, new DefaultClaimSet(Claim.CreateNameClaim(this.principal.Identity.Name)));41       evaluationContext.Properties["Principal"] = this.principal;42       return true;43     }44 45     #endregion46   }47 }

6、配置WCF

<system.serviceModel>  <bindings>   <wsHttpBinding>    <binding name="WSHttpBinding_OpenApi" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />     <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />     <security mode="Message">      <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />      <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" />     </security>    </binding>   </wsHttpBinding>  </bindings>  <behaviors>   <endpointBehaviors>    <behavior name="WCFRescourcesServer.OpenApiAspNetAjaxBehavior">     <enableWebScript />    </behavior>    <behavior name="WCFRescourcesServer.Services1Behavior">         </behavior>   </endpointBehaviors>   <serviceBehaviors>    <behavior name="myS">     <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />     <serviceDebug includeExceptionDetailInFaults="false" />     <serviceAuthorization serviceAuthorizationManagerType="WCFRescourcesServer.Code.IdefavAuthorizationManager, WCFRescourcesServer" principalPermissionMode="Custom" />    </behavior>   </serviceBehaviors>  </behaviors>  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />  <services>   <service name="WCFRescourcesServer.Service1" behaviorConfiguration="myS">    <endpoint address="" behaviorConfiguration="WCFRescourcesServer.Services1Behavior" binding="wsHttpBinding" contract="WCFRescourcesServer.IService1" />   </service>  </services> </system.serviceModel>

 

 

下面这段是关键的一句,配置WCF访问验证

<serviceAuthorization serviceAuthorizationManagerType="WCFRescourcesServer.Code.IdefavAuthorizationManager, WCFRescourcesServer" principalPermissionMode="Custom"/>

二、创建WCFClient访问WCF服务

创建一个IdefavOAuth2Client的Asp.net项目然后添加服务器引用

 

访问WCF代码如下:

 1 protected async void Button1_Click(object sender, EventArgs e) 2     { 3       var authServer = new AuthorizationServerDescription() 4       { 5          6         TokenEndpoint = new Uri("http://localhost:53022/OAuth/token "), 7         ProtocolVersion = ProtocolVersion.V20 8       }; 9       //var wcf= new UserAgentClient(authServer, "idefav", "1");10       WebServerClient Client= new WebServerClient(authServer, "idefav", "1");11 12       var code =await Client.GetClientAccessTokenAsync(new string[] { "http://localhost:55044/IService1/DoWork" });13       string token = code.AccessToken;14       Service1Reference.Service1Client service1Client=new Service1Client();15       var httpRequest = (HttpWebRequest)WebRequest.Create(service1Client.Endpoint.Address.Uri);16       ClientBase.AuthorizeRequest(httpRequest,token);17       var httpDetails = new HttpRequestMessageProperty();18       httpDetails.Headers[HttpRequestHeader.Authorization] = httpRequest.Headers[HttpRequestHeader.Authorization];19       20       using (var scope = new OperationContextScope(service1Client.InnerChannel))21       {22         23         if (OperationContext.Current.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))24         {25           OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpDetails;26         }27         else28         {29           OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpDetails);30         }31         32         Button1.Text= service1Client.DoWork();33       }34 35 36     }

注意:

标示的地方是可以从服务引用生成的代码上面看的到

 

当然这个Scope可以在WCF中配置

如果这里客户端和资源服务器不一致也会拒绝访问

 

我们来测试一下,把端口改成55045然后运行项目

 

结果:

 

 

 

最后,还有个注意点

DotNetOpenAuth v5.0.0-alpha3 从Nuget上面安装的有Bug,需要去github下载源代码然后编译成dll替换掉Nuget的dll

我已经编译好了一份,百度网盘:

链接:http://pan.baidu.com/s/1jGlMZye 密码:hw2o

 

 

这里的是WCF资源服务器以及客户端访问

 

下篇将会讲WebAPI形式的资源服务器