zoukankan      html  css  js  c++  java
  • 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形式的资源服务器

  • 相关阅读:
    centos crash debug
    go get Unknown SSL protocol error in connection to gopkg.in
    Tensorflow serving with Kubernetes
    Spring 集成 Swagger UI
    Docker Registry V2 Garbage Collection
    Docker Registry V2 with Nginx
    Zabbix磁盘性能监控
    Zabbix CPU utilization监控参数
    Windows挂载Gluster复制卷
    Redis持久化存储(三)
  • 原文地址:https://www.cnblogs.com/idefav2010/p/WCFResourcesServer.html
Copyright © 2011-2022 走看看