为了账号安全,请及时绑定邮箱和手机立即绑定

ASP.NET OWIN OpenID Connect 不创建用户身份验证

ASP.NET OWIN OpenID Connect 不创建用户身份验证

C#
MYYA 2022-12-24 12:16:59
我有一个 ASP.NET 4.6 Web 应用程序,我正在尝试使用 OWIN 添加 OpenId Connect。我添加了我的 Owin 启动类,一切似乎都配置正确,但我遇到的问题是从未创建 ASP Identity/Authenticated 用户。我最终陷入无限循环,OpenId 回调页面重定向回原始页面,然后再重定向到登录页面,等等。这是我的启动类:public void Configuration(IAppBuilder app)    {     app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);        app.UseKentorOwinCookieSaver();        app.UseCookieAuthentication(new CookieAuthenticationOptions        {            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,            LoginPath = new PathString("/Login.aspx"),            ExpireTimeSpan = TimeSpan.FromDays(7)        });        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions        {                            ClientId = _clientId,            ClientSecret = _clientSecret,            Authority = _authority,            RedirectUri = _redirectUri, // LoginCallback            PostLogoutRedirectUri = "http://localhost:60624/Logout.aspx",            ResponseType = OpenIdConnectResponseType.CodeIdToken,            Scope = "openid profile email",            TokenValidationParameters = new TokenValidationParameters            {                NameClaimType = "name"            },        });    }
查看完整描述

3 回答

?
千万里不及你

TA贡献1784条经验 获得超9个赞

是的,我不得不在 VB.Net 中为此工作获得概念证明,这有点痛苦。这是我的测试代码(即不是生产代码),它基于我看到的其他一些 C# 互联网示例:


Imports System.Security.Claims

Imports System.Threading.Tasks

Imports IdentityModel

Imports IdentityModel.Client

Imports Microsoft.AspNet.Identity

Imports Microsoft.AspNet.Identity.Owin

Imports Microsoft.IdentityModel.Protocols.OpenIdConnect

Imports Microsoft.Owin

Imports Microsoft.Owin.Security

Imports Microsoft.Owin.Security.Cookies

Imports Microsoft.Owin.Security.Notifications

Imports Microsoft.Owin.Security.OAuth

Imports Microsoft.Owin.Security.OpenIdConnect

Imports Owin


Partial Public Class Startup

    Private Shared _oAuthOptions As OAuthAuthorizationServerOptions

    Private Shared _publicClientId As String


    Private Shared _clientId As String

    Private Shared _clientSecret As String


    ' Enable the application to use OAuthAuthorization. You can then secure your Web APIs

    Shared Sub New()


        _clientId = System.Configuration.ConfigurationManager.AppSettings("OAuth:ClientID").ToString()

        _clientSecret = System.Configuration.ConfigurationManager.AppSettings("OAuth:SecretKey").ToString()


        PublicClientId = _clientId


        OAuthOptions = New OAuthAuthorizationServerOptions() With {

            .TokenEndpointPath = New PathString("/Token"), 'New PathString("https://authtesteria.domain.com/as/token.oauth2"), ' 

            .AuthorizeEndpointPath = New PathString("/Account/Authorize"), 'New PathString("https://authtesteria.domain.com/as/authorization.oauth2"), '

            .Provider = New ApplicationOAuthProvider(PublicClientId),

            .AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),

            .AllowInsecureHttp = True

        }

    End Sub


    Public Shared Property OAuthOptions() As OAuthAuthorizationServerOptions

        Get

            Return _oAuthOptions

        End Get

        Private Set

            _oAuthOptions = Value

        End Set

    End Property


    Public Shared Property PublicClientId() As String

        Get

            Return _publicClientId

        End Get

        Private Set

            _publicClientId = Value

        End Set

    End Property


    ' For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864

    Public Sub ConfigureAuth(app As IAppBuilder)

        ' Configure the db context, user manager and signin manager to use a single instance per request

        app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)

        app.CreatePerOwinContext(Of ApplicationUserManager)(AddressOf ApplicationUserManager.Create)

        app.CreatePerOwinContext(Of ApplicationSignInManager)(AddressOf ApplicationSignInManager.Create)


        ' Enable the application to use a cookie to store information for the signed in user

        ' and to use a cookie to temporarily store inforation about a user logging in with a third party login provider

        ' Configure the sign in cookie

        ' OnValidateIdentity enables the application to validate the security stamp when the user logs in.

        ' This is a security feature which is used when you change a password or add an external login to your account.

        app.UseCookieAuthentication(New CookieAuthenticationOptions() With {

            .AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,

            .Provider = New CookieAuthenticationProvider() With {

                .OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, ApplicationUser)(

                    validateInterval:=TimeSpan.FromMinutes(30),

                    regenerateIdentity:=Function(manager, user) user.GenerateUserIdentityAsync(manager))},

            .LoginPath = New PathString("/Account/Login")})



        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie)


        ' Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.

        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5))


        ' Enables the application to remember the second login verification factor such as phone or email.

        ' Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.

        ' This is similar to the RememberMe option when you log in.

        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie)


        ' Enable the application to use bearer tokens to authenticate users

        app.UseOAuthBearerTokens(OAuthOptions)


        Dim controller As New AccountController()


        'Dim validator As OpenIdConnectProtocolValidator = New OpenIdConnectProtocolValidator()

        'validator.ShowPII = False


        Dim oidcAuth As New Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions() With {

            .ClientId = _clientId,

            .ClientSecret = _clientSecret,

            .Authority = "https://authtesteria.domain.com",

            .Notifications = New Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications() With {

                .RedirectToIdentityProvider = AddressOf OnRedirectToIdentityProvider,

                .MessageReceived = AddressOf OnMessageReceived,

                .SecurityTokenReceived = AddressOf OnSecurityTokenReceived,

                .SecurityTokenValidated = AddressOf OnSecurityTokenValidated,

                .AuthorizationCodeReceived = AddressOf OnAuthorizationCodeReceived,

                .AuthenticationFailed = AddressOf OnAuthenticationFailed

        }}

        app.UseOpenIdConnectAuthentication(oidcAuth)


    End Sub


    Private Function OnRedirectToIdentityProvider(arg As RedirectToIdentityProviderNotification(Of Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task

        Debug.WriteLine("*** RedirectToIdentityProvider")


        If arg.ProtocolMessage.RequestType = Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Logout Then

            Dim idTokenHint = arg.OwinContext.Authentication.User.FindFirst("id_token")


            If idTokenHint IsNot Nothing Then

                arg.ProtocolMessage.IdTokenHint = idTokenHint.Value

            End If

        End If

        Return Task.FromResult(0)

    End Function


    Private Function OnMessageReceived(arg As MessageReceivedNotification(Of Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task

        Debug.WriteLine("*** MessageReceived")

        Return Task.FromResult(0)

    End Function


    Private Function OnAuthorizationCodeReceived(arg As AuthorizationCodeReceivedNotification) As Task

        Debug.WriteLine("*** AuthorizationCodeReceived")

        'Upon successful sign in, get & cache a token if you want here

        Return Task.FromResult(0)

    End Function


    Private Function OnAuthenticationFailed(arg As AuthenticationFailedNotification(Of Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task

        Debug.WriteLine("*** AuthenticationFailed")

        Return Task.FromResult(0)

    End Function


    Private Function OnSecurityTokenReceived(arg As SecurityTokenReceivedNotification(Of Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task

        Debug.WriteLine("*** SecurityTokenReceived")

        Return Task.FromResult(0)

    End Function


    Private Async Function OnSecurityTokenValidated(arg As SecurityTokenValidatedNotification(Of Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task

        Debug.WriteLine("*** SecurityTokenValidated")

        'Verify the user signing in should have access or not.  Here I just pass folk thru.

        Dim nid = New ClaimsIdentity(

              DefaultAuthenticationTypes.ApplicationCookie, 'arg.AuthenticationTicket.Identity.AuthenticationType,

              ClaimTypes.GivenName,

              ClaimTypes.Role)


        Dim tokenClient = New TokenClient("https://authtesteria.domain.com/as/token.oauth2",

             _clientId,

             _clientSecret)


        Dim tokenResponse = Await tokenClient.RequestAuthorizationCodeAsync(arg.ProtocolMessage.Code, arg.ProtocolMessage.RedirectUri)


        ' get userinfo data

        Dim userInfoClient = New IdentityModel.Client.UserInfoClient("https://authtesteria.domain.com/idp/userinfo.openid")


        Dim userInfo = Await userInfoClient.GetAsync(tokenResponse.AccessToken)

        userInfo.Claims.ToList().ForEach(Sub(ui) nid.AddClaim(New Claim(ui.Type, ui.Value)))


        '' keep the id_token for logout

        'nid.AddClaim(New Claim("id_token", arg.ProtocolMessage.IdToken))


        '' add access token for sample API

        'nid.AddClaim(New Claim("access_token", arg.ProtocolMessage.AccessToken))


        '' keep track of access token expiration

        'nid.AddClaim(New Claim("expires_at", DateTimeOffset.Now.AddSeconds(Integer.Parse(arg.ProtocolMessage.ExpiresIn)).ToString()))


        '' add some other app specific claim

        'nid.AddClaim(New Claim("app_specific", "some data"))


        nid.AddClaim(New Claim(ClaimTypes.Role, "group1"))


        arg.AuthenticationTicket = New AuthenticationTicket(nid, arg.AuthenticationTicket.Properties)

        arg.AuthenticationTicket.Properties.RedirectUri = HttpContext.Current.Session("PageRedirect").ToString() 

    End Function

End Class

现在我像这样触发登录:


Private Sub SomePageName_Load(sender As Object, e As EventArgs) Handles Me.Load

    If Not IsPostBack Then

        If User.Identity.IsAuthenticated Then

            Console.WriteLine(User.Identity.GetUserName())

        Else

            Session("PageRedirect") = Request.Url

            Response.Redirect("/")

        End If

    End If

End Sub

我们有几点不同:

  1. 我使用 OnSecurityTokenValidated 但我不确定这是否重要

  2. 我用当前页面的 Request.Url 填充会话变量,

  3. 然后在启动时在 OnSecurityTokenValidated 的通知参数中使用它:arg.AuthenticationTicket.Properties.RedirectUri = …(参见我的代码)。

希望这会有所帮助。享受!


查看完整回答
反对 回复 2022-12-24
?
jeck猫

TA贡献1909条经验 获得超7个赞

我设置了 RedeemCode=True 和 SaveTokens=True 并将其放入通知中,我终于能够让它工作了。所有的例子都没有包括这个,我不确定为什么,但也许它是代码流所必需的。您不必重新添加声明,否则会重复声明。


如果您希望自动填充 User.Identity.Name,也不要忘记设置 TokenValidationParameters NameClaimType="name"。


SecurityTokenValidated = (context) =>

            {

                var ctx = context.OwinContext;

                

                var applicationCookieIdentity = new ClaimsIdentity(context.AuthenticationTicket.Identity, null, DefaultAuthenticationTypes.ApplicationCookie, null, null);

                ctx.Authentication.SignIn(applicationCookieIdentity);


                return Task.FromResult(0);

            },


查看完整回答
反对 回复 2022-12-24
?
LEATH

TA贡献1936条经验 获得超6个赞

就我而言,我根本不需要向Notifications启动文件中添加任何内容。我错过了这个:


app.UseCookieAuthentication(new CookieAuthenticationOptions() 

{

    CookieManager = new SystemWebCookieManager()

});

Katana 中有一些错误会阻止 cookie 被正确保存,因此添加这一行代码后,经过三天的查找解决了我的问题!


查看完整回答
反对 回复 2022-12-24
  • 3 回答
  • 0 关注
  • 93 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信