• DotNetOpenAuth实践之WCF资源服务器配置


    系列目录:

    DotNetOpenAuth实践系列(源码在这里)

    上一篇我们写了一个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 Members
    23 
    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         #endregion
    32 
    33         #region IAuthorizationPolicy Members
    34 
    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         #endregion
    46     }
    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                 else
    28                 {
    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形式的资源服务器

  • 相关阅读:
    [转载]HashSet的存储机制
    Java基础加强
    [转载]JDK的动态代理深入解析(Proxy,InvocationHandler)
    Java语言基础Html
    Java语言基础JavaScript
    多线程数据与控制同步
    Expression Tree Basics表达式树基础
    调试优化利器ASP.NET 跟踪
    css position relative ,absolute ,float
    .net date /日期格式化
  • 原文地址:https://www.cnblogs.com/idefav2010/p/WCFResourcesServer.html
Copyright © 2020-2023  润新知