DotNetOpenAuth 使用指南

时间:2022-06-05 00:28:02

这几天一直在研究DotNetOpenAuth,源码处处是坑啊!写此文只为大家更顺利掌握DotNetOpenAuth使用方法,尽量少走弯路。

说明一下:我的环境是Win7 64   VS2015 update2

废话少说,踏坑开始:

新建项目:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

右键引用:

DotNetOpenAuth 使用指南

搜索 dotnetopenauth,勾选包括预发行版:

DotNetOpenAuth 使用指南

提示安装一大堆东西:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

可以看到Web.config添加了很多东西,稍后再讲这个

diff --git a/MvcOAuthServer/MvcAuth2Client/Web.config b/MvcOAuthServer/MvcAuth2Client/Web.config
index 5da5b22..ef7ea07
--- a/MvcOAuthServer/MvcAuth2Client/Web.config
+++ b/MvcOAuthServer/MvcAuth2Client/Web.config
@@ -, +, @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   For more information on how to configure your ASP.NET application, please visit
   http://go.microsoft.com/fwlink/?LinkId=301880
@@ -, +, @@
   <configSections>
     <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
     <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
-  </configSections>
+  <sectionGroup name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection, DotNetOpenAuth.Core">
+            <section name="messaging" type="DotNetOpenAuth.Configuration.MessagingElement, DotNetOpenAuth.Core" requirePermission="false" allowLocation="true" />
+            <section name="reporting" type="DotNetOpenAuth.Configuration.ReportingElement, DotNetOpenAuth.Core" requirePermission="false" allowLocation="true" />
+        <section name="oauth" type="DotNetOpenAuth.Configuration.OAuthElement, DotNetOpenAuth.OAuth" requirePermission="false" allowLocation="true" /><section name="openid" type="DotNetOpenAuth.Configuration.OpenIdElement, DotNetOpenAuth.OpenId" requirePermission="false" allowLocation="true" /></sectionGroup></configSections>
   <connectionStrings>
-    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MvcAuth2Client-20160504102822.mdf;Initial Catalog=aspnet-MvcAuth2Client-20160504102822;Integrated Security=True"
-      providerName="System.Data.SqlClient" />
+    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MvcAuth2Client-20160504102822.mdf;Initial Catalog=aspnet-MvcAuth2Client-20160504102822;Integrated Security=True" providerName="System.Data.SqlClient" />
   </connectionStrings>
   <appSettings>
     <add key="webpages:Version" value="3.0.0.0" />
@@ -, +, @@
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
-        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
+        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
         <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
       </dependentAssembly>
     </assemblyBinding>
-  </runtime>
+  <!-- This prevents the Windows Event Log ,  and  references relink
+             to MVC  so libraries such  will work with it.
+        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+            <dependentAssembly>
+                <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+                <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+            </dependentAssembly>
+        </assemblyBinding>
+         --></runtime>
   <entityFramework>
     <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
       <parameters>
@@ -, +, @@
       <compiler language=" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
     </compilers>
   </system.codedom>
-</configuration>
\ No newline at end of file
+<system.net>
+        <defaultProxy enabled="true" />
+        <settings>
+            <!-- This setting causes .NET to check certificate revocation lists (CRL)
+                 before trusting HTTPS certificates.  But this setting tends to not
+                 be allowed in shared hosting environments. -->
+            <!--<servicePointManager checkCertificateRevocationList="true"/>-->
+        </settings>
+    </system.net><dotNetOpenAuth>
+        <messaging>
+            <untrustedWebRequest>
+                <whitelistHosts>
+                    <!-- Uncomment to enable communication with localhost (should generally not activate in production!) -->
+                    <!--<add name="localhost" />-->
+                </whitelistHosts>
+            </untrustedWebRequest>
+        </messaging>
+        <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
+        <reporting enabled="true" />
+    <!-- This is an optional configuration section where aspects of dotnetopenauth can be customized. --><!-- For a complete set of configuration options see http://www.dotnetopenauth.net/developers/code-snippets/configuration-options/ --><openid>
+        <provider>
+            </provider><relyingParty>
+                <security requireSsl="false">
+                    <!-- Uncomment the trustedProviders tag if your relying party should only accept positive assertions from a closed set of OpenID Providers. -->
+                    <!--<trustedProviders rejectAssertionsFromUntrustedProviders="true">
+                        <add endpoint="https://www.google.com/accounts/o8/ud" />
+                    </trustedProviders>-->
+                </security>
+                <behaviors>
+                    <!-- The following OPTIONAL behavior allows RPs to use SREG only, but be compatible
+                         with OPs that use Attribute Exchange (in various formats). -->
+                    <add type="DotNetOpenAuth.OpenId.RelyingParty.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth.OpenId.RelyingParty" />
+                </behaviors>
+            </relyingParty></openid></dotNetOpenAuth><uri>
+        <!-- The uri section is necessary to turn on .NET 3.5 support for IDN (international domain names),
+             which is necessary for OpenID urls with unicode characters in the domain/host name.
+             It  escaping mode, which OpenID and OAuth require. -->
+        <idn enabled="All" />
+        <iriParsing enabled="true" />
+    </uri></configuration>
\ No newline at end of file

其实真正用到的只有这三个:

DotNetOpenAuth 使用指南

可以把其它的删掉。

添加一个空控制器:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

修改AuthorizeController的内容:

 public class AuthorizeController : Controller
    {
        private static readonly WebServerClient Client;
        private static AuthorizationServerDescription authServerDescription = new AuthorizationServerDescription
        {
            TokenEndpoint = new Uri("http://localhost:50172/OAuth/Token"),
            AuthorizationEndpoint = new Uri("http://localhost:50172/OAuth/Authorize"),
        };
        static AuthorizeController()
        {
            Client = new WebServerClient(authServerDescription, "sampleconsumer", "samplesecret");
        }

        public async Task<ActionResult> Index()
        {
            IAuthorizationState authorization = await Client.ProcessUserAuthorizationAsync(Request, Response.ClientDisconnectedToken);
            if (authorization == null)
            {
                List<string> scopes = new List<string>();
                scopes.Add("http://tempuri.org/IDataApi/GetName");
                var request =
                                await Client.PrepareRequestUserAuthorizationAsync(scopes, cancellationToken: Response.ClientDisconnectedToken);
                await request.SendAsync();
                return Content("done");
            }
            else
            {
                TimeSpan timeLeft = authorization.AccessTokenExpirationUtc.Value - DateTime.UtcNow;
                string token = authorization.AccessToken;
                ));
                return Content(result);
            }
        }
    }

运行吧http://localhost:18180/Authorize

报错了吧:

DotNetOpenAuth 使用指南

是不是想哭,这个问题我在网上找了很久,还是在http://*.com/  上找到了答案

凶手就是System.Net.Http.Formatting

DotNetOpenAuth 使用指南

这个是Microsoft.AspNet.WebApi.Client 包里的,DotNetOpenAuth所依赖的版本是4.0.0,所以要替换下,打开Nuget包管理器,搜索Microsoft.AspNet.WebApi.Client,

在右侧版本下拉框中拉到最下面,选4.0.20505

DotNetOpenAuth 使用指南

结果又报错了:

DotNetOpenAuth 使用指南

这里需要在选项中依赖项行为从最低改成忽略依赖项:

DotNetOpenAuth 使用指南

再点更新就出现了熟悉的窗口了:

DotNetOpenAuth 使用指南

可以看到Web.config中的变化:

      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>

确认下版本:

DotNetOpenAuth 使用指南

再次运行,又报错了

DotNetOpenAuth 使用指南

是不是又要哭了,没关系,接着来。

打开:https://github.com/DotNetOpenAuth

先看 DotNetOpenAuth.Samples

先别着急下,看看这个:

DotNetOpenAuth 使用指南

看到这个标志就别下载了,下载下来后生成是通不过的,怎么样,是不是又想哭了,官方给的样例都是跑不起来的

那看另外一个源码吧:

https://github.com/DotNetOpenAuth/DotNetOpenAuth

DotNetOpenAuth 使用指南

还好这个是编译通过的,下到本地,解压,打开,重新生成,这里会自动加载程序包

DotNetOpenAuth 使用指南

如果你的VS没有开启自动下载程序包的话需要手动开启:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

提示重新生成成功,可是在输出窗口又出了一堆错:

DotNetOpenAuth 使用指南

看到这里是不是要疯了。。。

很多人在这个时候就崩溃了,我也是,可是我在另外一台电脑上输出窗口是关闭了的,我没看到这个提示,于是我把OAuthAuthorizationServer设置为启动项目就跑起来了:

DotNetOpenAuth 使用指南

结果发现即便输出窗口报错也是能跑起来的,这个时候你的内心一定是极度崩溃的。。。

好了,服务端开启后再开启客户端:OAuthClient

然后你就会发现源码里的这个跑起来是没有问题的,并没有报我们自己项目里的那个错误,好吧,这个时候就要看看到底是哪里不同

还是这三个dll:

DotNetOpenAuth.Core

DotNetOpenAuth.OAuth2

DotNetOpenAuth.OAuth2.Client

在VS中看两个项目中都是5.0.0.0,完全一样,但当你在Windows中打开时就有区别了:

DotNetOpenAuth 使用指南DotNetOpenAuth 使用指南

左边是自己项目里的,右边是源码中引用的,废话不多说,把自己项目里的这三个都替换成源码里的

DotNetOpenAuth 使用指南

再次运行:http://localhost:18180/Authorize

DotNetOpenAuth 使用指南

提示要求Https,这里可以改下配置

修改dotNetOpenAuth.messaging节点:

<!-- Relaxing SSL requirements is useful for simple samples, but NOT a good idea in production. -->
        <messaging relaxSslRequirements="true">
            <untrustedWebRequest>
                <whitelistHosts>
                    <!-- Uncomment to enable communication with localhost (should generally not activate in production!) -->
                    <!--<add name="localhost" />-->
                </whitelistHosts>
            </untrustedWebRequest>
        </messaging>

但是生产环境不建议这么做,稍后会介绍搭建Https。

修改后再运行就没问题了,当然,现在还没有搭建服务端,那就先用源码的服务端来测试吧。

修改源码-->Sample-->OAuth2-->OAuthAuthorizationServer  中Web.config中的数据库连接:

<connectionStrings>
        <add name="DatabaseConnectionString"
            connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DotNetOpenAuth;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
            providerName="System.Data.SqlClient"/>
    </connectionStrings>

运行,Home中有一个创建数据库按钮

DotNetOpenAuth 使用指南

点击即可创建数据库

DotNetOpenAuth 使用指南

此时可以看到数据库新增了5张表:

DotNetOpenAuth 使用指南

并增加了测试Client:

DotNetOpenAuth 使用指南

此时再打开我们自己的网站:http://localhost:18180/Authorize

会跳转到登录页面:

DotNetOpenAuth 使用指南

要求输入OpenID,这里的OpenID就是授权的系统,一般是一个Url,因为URL是唯一的,这里先用源码中提供的:http://localhost:4864/

这里需要说明一下,源码启动后会在IIS Express中启动多个网站:

DotNetOpenAuth 使用指南

输入OpenID后点击登录:

DotNetOpenAuth 使用指南

会跳转到OpenID网站的登录页面,如果是Google的话就会跳转到Google的登录页面:

DotNetOpenAuth 使用指南

这里使用下面的用户名和密码登录即可:

DotNetOpenAuth 使用指南

登录后会询问用户是否可以授权:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

授权后我们就拿到access token 了,之后就可以使用token访问其它资源了。

DotNetOpenAuth 使用指南

再看一下数据库的变化:

DotNetOpenAuth 使用指南

到这里差不多就可以了。

顺便看看怎么使用Google和Facebook的服务:

需要引用DotNetOpenAuth.ApplicationBlock,这个dll在源码里可以找到。

添加GoogleController:

写入代码:

public class GoogleController : Controller
    {
        private static readonly GoogleClient googleClient = new GoogleClient
        {
            ClientIdentifier = ConfigurationManager.AppSettings["googleClientID"],
            ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(ConfigurationManager.AppSettings["googleClientSecret"]),
        };

        public async Task<ActionResult> Index()
        {
            IAuthorizationState authorization = await googleClient.ProcessUserAuthorizationAsync(Request, Response.ClientDisconnectedToken);
            if (authorization == null)
            {
                var request = await googleClient.PrepareRequestUserAuthorizationAsync(scopes: new[]
                {
                    GoogleClient.Scopes.UserInfo.Profile,
                    GoogleClient.Scopes.UserInfo.Email
                }, cancellationToken: Response.ClientDisconnectedToken);
                await request.SendAsync();
                Response.End();
                return Content("Done");
            }
            else
            {
                IOAuth2Graph oauth2Graph = await googleClient.GetGraphAsync(authorization, cancellationToken: Response.ClientDisconnectedToken);

                var name = HttpUtility.HtmlEncode(oauth2Graph.Email);
                return Content("成功授权! Email: " + name);
            }
        }
    }

在web.config中加入配置:

DotNetOpenAuth 使用指南

打开https://console.developers.google.com/apis

设置回调地址:

DotNetOpenAuth 使用指南

因为Google要求是Https的,所以我们的服务器也要配置Https:

打开项目属性,启用SSL

DotNetOpenAuth 使用指南DotNetOpenAuth 使用指南

启动网站,导航到:https://localhost:44337/google

页面跳转到Google进行登录:

DotNetOpenAuth 使用指南

登录成功询问授权:

DotNetOpenAuth 使用指南

DotNetOpenAuth 使用指南

然后就可以调用Google的服务了,比如这里可以拿到Email。

使用Facebook登录的原理是一样的:

public class FacebookController : Controller
    {
        private static readonly FacebookClient facebookClient = new FacebookClient
        {
            ClientIdentifier = ConfigurationManager.AppSettings["facebookAppID"],
            ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(ConfigurationManager.AppSettings["facebookAppSecret"]),
        };
        public async Task<ActionResult> Index()
        {
            IAuthorizationState authorization = await facebookClient.ProcessUserAuthorizationAsync(Request, Response.ClientDisconnectedToken);
            if (authorization == null)
            {
                var request = await facebookClient.PrepareRequestUserAuthorizationAsync(scopes: new[]
                {
                    FacebookClient.Scopes.Email,
                    FacebookClient.Scopes.UserBirthday,
                    //FacebookClient.Scopes.ReadFriendlists,
                    FacebookClient.Scopes.ReadInsights,
                    FacebookClient.Scopes.UserAboutMe,
                    //FacebookClient.Scopes.UserActivities
                },cancellationToken: Response.ClientDisconnectedToken);
                await request.SendAsync();
                Response.End();
                return Content("Done");
            }
            else
            {
                IOAuth2Graph oauth2Graph = await facebookClient.GetGraphAsync(authorization, cancellationToken: Response.ClientDisconnectedToken);
                //// IOAuth2Graph oauth2Graph = facebookClient.GetGraph(authorization, new[] { FacebookGraph.Fields.Defaults, FacebookGraph.Fields.Email, FacebookGraph.Fields.Picture, FacebookGraph.Fields.Birthday });

                var name = HttpUtility.HtmlEncode(oauth2Graph.Name);
                return Content(name);
            }
        }
    }

DotNetOpenAuth 使用指南DotNetOpenAuth 使用指南

当然,可以看到上面的代码中注释了两行,原因如下:

DotNetOpenAuth 使用指南

这就是使用DotNetOpenAuth的Client进行认证,当然你也可以自己实现,先到授权服务器拿到授权码,然后带着这个授权码去获取token,拿到token后访问接口服务

只不过实现个过程比较繁琐,而OAUTH2是个标准,所以直接使用封装好的Client也没有什么问题。

下一篇会介绍使用DotNetOpenAuth搭建自己的授权服务器。