5

我正在尝试编写一个使用混合身份验证方案的 ASP.NET 应用程序。用户可以将其用户名和密码哈希存储在 UserStore 中,也可以通过 Azure Active Directory 进行身份验证。

我已经创建了如图所示的登录表单。它具有标准UserNamePassword输入,还具有“通过 Active Directory 登录”按钮。

在此处输入图像描述

这很好用。

现在解决问题:应用程序的主页具有该[Authorize]属性。

public class DefaultController : Controller
{
    [Authorize]
    public ViewResult Index()
    { 
    // Implementation
    }
}

如果用户未登录,我希望它重定向到页面Account/Login,允许用户选择身份验证方法。

一旦我添加IAppBuilder.UseOpenIdConnectAuthentication到管道设置中,它就不再重定向到该页面。相反,它直接进入 Microsoft 登录页面。

如何配置它以便 OpenID 身份验证成为系统的一部分,但允许我指定在用户未通过身份验证时如何执行重定向?

这是我设置管道的代码:

appBuilder.SetDefaultSignInAsAuthticationType(CookieAuthenticationDefaults.AuthenticationType_;
var cookieAuthenticationOptions = new CookieAuthenticationOptions
{
     AuthenticationType = DefaultAuthenticationType.ApplicationCookie,
     LoginPath = new Microsoft.Owin.PathString("/Account/Login"),
     Provider = new Security.CookieAuthenticationProvider()
};
appBuilder.UseCookieAuthentication(cookieAuthenticationOptions);
// Now the OpenId authentication
var notificationHandlers = new OpenIdConnectAuthenticationNotificationHandlers 
{
   AuthorizationCodeReceived = async(context) => {
       var jwtSecurityToken = context.JwtSecurityToken;
       // I've written a static method to convert the claims
       // to a user
       var user = await GetOrCreateUser(context.OwinContext, jwtSecurityToken.Claims);
       var signInManager = context.OwinContext.Get<SignInManager>();
       await signInManager.SignInAsync(user, true, false);
   }
}
var openIdOptions = new OpenIdConnectAuthenticationOptions
{
     ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
     Authority = "https://login.microsoftonline.com/xxxxx.onmicrosoft.com",
     PostLogoutRedirectUri = "https://localhost:52538/Account/Login",
     Notifications = notifcationHandlers
}
appBuilder.UseOpenIdConnectAuthentication(openIdOptions);

当您单击“Active Directory 登录”时,它会发布到“Account/SignInWithOpenId”

public ActionResult SignInWithOpenId()
{
    // Send an OpenID Connect sign-in request.
    if (!Request.IsAuthenticated)
    {
        var authenticationProperties = new AuthenticationProperties
        {
            RedirectUri = "/"
        };
        HttpContext.GetOwinContext().Authentication.Challenge
        (
            authenticationProperties,
            OpenIdConnectAuthenticationDefaults.AuthenticationType
        );
        return new EmptyResult();
    }
    else
    {
        return RedirectToAction("Index", "Default");
    }
}
4

3 回答 3

11

调用IAppBuilder.UseOpenIdConnectAuthentication(...)将 Owin 中间件组件放入管道中。当 ASP.NET MVC 返回 401(未经授权)的 HttpResponse 时,Owin 中间件组件会检测到这一点并将其更改为 Http Redirect(代码 302),并且重定向路径是 Open Id 提供程序。

但是有一种方法可以解决这个问题:在中间件组件执行重定向之前,它会调用 callback RedirectToIdentityProvider。从这里,您可以覆盖此重定向。

这是我的代码,它覆盖重定向,除非它来自请求路径Account/SignInWithOpenId

var notificationHandlers = new OpenIdConnectAuthenticationNotifications
{
    AuthorizationCodeReceived = async(context) => {
       // Sign in the user here
    },
    RedirectToIdentityProvider = (context) => {
        if(context.OwinContext.Request.Path.Value != "/Account/SignInWithOpenId")
        {
             context.OwinContext.Response.Redirect("/Account/Login");
             context.HandleResponse();
        }
        return Task.FromResult(0);
    }
}
var openIdOptions = new OpenIdConnectAuthenticationOptions
{
     ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
     Authority = "https://login.microsoftonline.com/xxxxx.onmicrosoft.com",
     PostLogoutRedirectUri = "https://localhost:52538/Account/Login",
     Notifications = notifcationHandlers
}
appBuilder.UseOpenIdConnectAuthentication(openIdOptions);
于 2017-04-26T10:44:25.873 回答
1

请尝试移动UseOpenIdConnectAuthentication之前的UseCookieAuthentication,然后它将用户重定向到“登录”页面。

// Now the OpenId authentication
var notificationHandlers = new OpenIdConnectAuthenticationNotificationHandlers 
{
  // Handler methods here
}
var openIdOptions = new OpenIdConnectAuthenticationOptions
{
     ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
     Authority = "https://login.microsoftonline.com/xxxxx.onmicrosoft.com",
     PostLogoutRedirectUri = "https://localhost:52538/Account/Login",
     Notifications = notifcationHandlers
}
appBuilder.UseOpenIdConnectAuthentication(openIdOptions);

appBuilder.SetDefaultSignInAsAuthticationType(CookieAuthenticationDefaults.AuthenticationType_;
var cookieAuthenticationOptions = new CookieAuthenticationOptions
{
     AuthenticationType = DefaultAuthenticationType.ApplicationCookie,
     LoginPath = new Microsoft.Owin.PathString("/Account/Login"),
     Provider = new Security.CookieAuthenticationProvider()
};
appBuilder.UseCookieAuthentication(cookieAuthenticationOptions);

请让我知道它是否有帮助。

更新 :

或者您可以使用自定义授权属性来覆盖默认行为,例如:

    public class CustomAuthorizeAttribute: AuthorizeAttribute
    {
        public CustomAuthorizeAttribute(): base()
        {
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {

            }
            else
            {
                filterContext.HttpContext.Response.Redirect("Account/login");
            }              
        }
    }

然后只需将您的用法更改为:

[CustomAuthorize]
public ActionResult Index()
{
    return View();
}
于 2017-04-25T02:37:11.707 回答
0

如果您将 OIDC 的身份验证模式设置为 Passive,它应该只响应显式 Open ID Connect 请求(例如发布到 Account/SignInWithOpenId):

var openIdOptions = new OpenIdConnectAuthenticationOptions
{
     // ...
     AuthenticationMode = AuthenticationMode.Passive
}

来源: The OWIN OpenID Connect Middleware 的“Explicit use of Challenge and SignOut”部分

于 2020-07-27T17:32:23.947 回答