如何将 OpenID 结合 Forms Authentication 添加到 MVC

Posted

技术标签:

【中文标题】如何将 OpenID 结合 Forms Authentication 添加到 MVC【英文标题】:How to add OpenID combined with Forms Authentication to MVC 【发布时间】:2020-11-06 06:04:55 【问题描述】:

我有一个使用 FormsAuthentication 进行身份验证的现有 MVC 项目。

除了已经可用的常规登录页面之外,我还需要合并使用 OpenID IDP 登录的选项。

我遇到的问题是按需挑战 IDP 并在收到声明后设置身份验证 cookie,但我找不到 cookie 没有粘贴的原因。流程似乎运行良好,我可以在 AuthorizationCodeReceived 回调中看到声明。

这是 Startup.Auth.cs 代码:

var notificationHandlers = new OpenIdConnectAuthenticationNotifications
        
            AuthorizationCodeReceived = (context) =>
            
                string username = context.AuthenticationTicket.Identity.FindFirst("preferred_username").Value;
                FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(60), true, "");
                string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
                context.Response.Cookies.Append(FormsAuthentication.FormsCookieName, encryptedTicket);

                return Task.FromResult(0);
            ,
            RedirectToIdentityProvider = (context) =>
            
                if (context.OwinContext.Request.Path.Value != "/Account/SignInWithOpenId")
                
                    context.OwinContext.Response.Redirect("/Account/Login");
                    context.HandleResponse();
                
                return Task.FromResult(0);
            
        ;

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        
            AuthenticationType = "oidc",
            SignInAsAuthenticationType = "Cookies",
            Authority = "xxxxxxxxx",
            ClientId = "MyClient",
            ClientSecret = "xxxxxxxx",
            RedirectUri = "http://localhost:52389/",
            PostLogoutRedirectUri = "http://localhost:52389/",
            ResponseType = "code id_token",
            Scope = "openid profile email roles",
            UseTokenLifetime = false,
            TokenValidationParameters = new TokenValidationParameters()
            
                NameClaimType = "preferred_username",
                RoleClaimType = "role"
            ,
            Notifications = notificationHandlers                
        );

        app.SetDefaultSignInAsAuthenticationType("Cookies");

        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        
            AuthenticationType = "Cookies",
            AuthenticationMode = AuthenticationMode.Passive,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider()
        );

        app.UseStageMarker(PipelineStage.Authenticate);

这里是 AccountController SignInWithOpenId 方法:

public ActionResult SignInWithOpenId()
    
        if (!Request.IsAuthenticated)
        
            HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);

            // If I don't have this line, reponse redirects to the forms authentication login... so maybe something is wrong here?
            return new HttpUnauthorizedResult("IDP");
        
        else
        
            return RedirectToAction("Index", "Default");
        
    

任何指针将不胜感激。谢谢。

【问题讨论】:

【参考方案1】:

这正是我目前正在尝试做的事情。如果我发现任何有用的东西,我会告诉你。

更新: 我最终在 MVC Web 应用程序中禁用了表单身份验证。我正在做一个概念验证,所以这不是一个硬性要求。我知道这不是你真正想要的。我成功使用 IdP 登录并重定向回 Web 应用程序。概念证明结束的地方是需要填充 HttpContext.User 对象。

【讨论】:

我通过更改 HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType); 进一步了解了这一点到 HttpContext.GetOwinContext().Authentication.Challenge("oidc");这使得挑战工作,然后在来自 IDP 的重定向上正确设置了 cookie 嗨@Naner,我完全按照您的代码进行操作,但我使用的是 Azure AD IDP。我有 的网络配置。所以登录页面的访问也被拒绝。有什么想法吗?【参考方案2】:

我能够在 .NET 4.7 中得到这个,或者至少是等效的。我的用例是大多数订阅者正在升级以通过 Azure AD B2C 登录,但我们有公共 PC,我们希望通过隐藏的 URL 手动声明进行身份验证。

我正在使用Microsoft.Owin.Security.OpenIDConnect和相关的包,Owin启动是标准的,虽然我会指出这一行:

app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

我不得不完全禁用 Forms 身份验证;当在 IIS 中启用匿名身份验证以外的任何其他功能时,我无法使其正常工作。

解决方案的核心实际上是我在这里找到的一个示例:How to use OWIN forms authentication without aspnet identity

    /* URL validated, add authenticated claim */
    var claims = new List<Claim>
    
        new Claim(ClaimTypes.Name, "PublicPC"),
        new Claim(ClaimTypes.Email, "PublicPC@example.org")
    ;
    var id = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationType);

    var ctx = HttpContext.Current.GetOwinContext();
    var authenticationManager = ctx.Authentication;
    authenticationManager.SignIn(id);

但至关重要的是,我需要指定 CookieAuthenticationDefaults.AuthenticationType,这是我在 Owin 启动时使用的。

【讨论】:

以上是关于如何将 OpenID 结合 Forms Authentication 添加到 MVC的主要内容,如果未能解决你的问题,请参考以下文章

将 OpenID (RPX)(可能还有 OAuth)用于 RESTful Web 服务

forms

微信小程序如何开发,怎么获取openID和用户信息

如何将数据切换与数据工具提示相结合?

AspNetCore With Angular SPA Authentication using the Authorization Code Flow

结合汉堡菜单和导航页面,Xamarin.Forms