处理AuthenticationResult来自同一页面中的不同提供者

Evi*_*lDr 6 asp.net openid dotnetopenauth liveid asp.net-4.5

我正在使用LiveID和Google提供商将OpenID集成到我现有的应用程序中.在我的登录页面上,除了原始登录字段之外,我还添加了"使用Google登录"和"使用Microsoft登录"按钮.

我可以成功读取上述两个提供商的AuthenticationResult数据,但是我是按照以下方式完成的...

对于新的登录按钮,我制作了一个返回URL,以便在用户返回时区分它们:

Protected Sub btn_google_Click(sender As Object, e As EventArgs) Handles btn_google.Click
    Dim client As New GoogleOpenIdClient
    Dim u As New System.Uri("http://www.mytest.com/login.aspx?action=signin&provider=google")
    client.RequestAuthentication(New HttpContextWrapper(HttpContext.Current), u)
End Sub

Protected Sub btn_live_Click(sender As Object, e As EventArgs) Handles btn_live.Click
    Dim client As New MicrosoftClient("xyz", "12345")
    Dim u As New System.Uri("http://www.mytest.com/login.aspx?action=signin&provider=microsoft")
    client.RequestAuthentication(New HttpContextWrapper(HttpContext.Current), u)
End Sub
Run Code Online (Sandbox Code Playgroud)

因此,当用户重定向回login.aspx时,我会进行以下检查以处理登录功能:

If Not Page.IsPostBack Then
    If Request.QueryString("action") IsNot Nothing AndAlso Request.QueryString("action").Trim = "signin" Then
        If Request.QueryString("provider") IsNot Nothing AndAlso Request.QueryString("provider").Trim <> String.Empty Then
            Select Case Request.QueryString("provider").Trim
                Case "microsoft"
                    Dim client As New MicrosoftClient("xyz", "12345")
                    Dim u As New System.Uri("http://www.mytest.com/loginlive.aspx?action=signin&provider=microsoft")
                    Dim result As DotNetOpenAuth.AspNet.AuthenticationResult = client.VerifyAuthentication(New HttpContextWrapper(HttpContext.Current), u)
                    ' remainder of logic removed
                    ' ...
                Case "google"
                    Dim client As New GoogleOpenIdClient
                    Dim result As DotNetOpenAuth.AspNet.AuthenticationResult = client.VerifyAuthentication(New HttpContextWrapper(HttpContext.Current))
                    ' remainder of logic removed
                    ' ...
            End Select
        End
    End
End If
Run Code Online (Sandbox Code Playgroud)

我的主要问题是,这是处理AuthenticationResults的好方法吗?或者,是否有更好/更安全/更聪明的方法来实现同样的目标?

小智 1

更好的方法是将抽象工厂模式与命令模式结合使用。这可以减少硬编码并且使代码松散耦合,因此您可以在将来扩展每个身份验证提供程序的功能。找到下面代码各部分的片段

“BaseAuthentication Provider”的抽象类

public abstract class BaseAuthenticationProvider
{
    //abstract Methods that need to be invoked from the concrete class, this need to be decided based on the functionality you need to achieve. This function would be invoked using the command pattern.
    // AuthorizeUser() : this method would be invoked to authorize the user from the provider

   //AuthenticateUser() : this method would be invoked once the user is redirected from the provider site.

    //abstract Properties that will hold the base information for the authentication provider, this need to be decided based on the functionality you need to achieve
    //CustomerSecret
    //CustomerConsumerKey
}
Run Code Online (Sandbox Code Playgroud)

使用以下代码片段为 Gooogle、Yahoo、Microsoft 等实现具体类。

public class GoogleAuthentication : BaseAuthenticationProvider
{
     public GoogleAuthentication()
     {
          //initialization
     }

     public void AuthorizeUser()
     {
          //code
     }

     public string CustomerSecret()
     {
          //code
     }

     public string CustomerConsumerKey()
     {
          //code
     }
}
Run Code Online (Sandbox Code Playgroud)

工厂类创建具体对象,以防止创建该工厂类的实例实现私有构造函数。

public class AuthenticationProviderFactory
{
     private AuthenticationProviderFactory()
     {
     }

     public static BaseAuthenticationProvider GetInstance(string Domain)
     {
          switch (Domain)
          {
               case "google":
                    return new GoogleAuthentication();
               case "yahoo":
                    return new YahooAuthentication();
           }
      }
 }
Run Code Online (Sandbox Code Playgroud)

Login.aspx :为每个身份验证提供程序提供按钮,为每个按钮设置“CommandName”的值并将所有按钮链接到同一事件处理程序

例如 btn_google.CommandName = "google"

Protected Sub AuthenticationProvider_Click(sender As Object, e As EventArgs) Handles btn_google.Click, btn_yahoo.Click
    AuthenticationProviderFactory.GetInstance(((Button)sender).CommandName).AuthorizeUser();
End Sub
Run Code Online (Sandbox Code Playgroud)

相应的 AuthorizeUser 方法将调用相应的提供商站点进行身份验证。当提供程序将用户重定向到返回 URL 时,对 Page_Load 事件应用相同的模式并从抽象类调用 Autheticate 方法。