ASP.NET Core 2.2和OIDC:当用户未经授权时,自动重定向到外部权限认证

3

我试图使用外部授权服务器通过OpenID Connect协议(具体来说是KeyCloak,但我认为这并不重要)来保护我的ASP.NET MVC Web 应用程序。
我找到的所有示例基本上都是安装Microsoft.AspNetCore.Authentication.OpenIdConnect NuGet包,并向启动类添加一些配置代码:

services
    .AddAuthentication()
    .AddOpenIdConnect(options =>
    {
        options.Authority = authUrl;
        options.ClientId = clientId;
        options.ClientSecret = clientSecret;
        options.ResponseType = OpenIdConnectResponseType.Code;
    });  

如果我在控制器操作中添加[Authorized]属性,当我尝试打开页面时,将重定向到系统页面/Identity/Account/Login,在其中“使用其他服务登录”部分显示了按钮OpenIdConnect,可通过远程身份验证服务器进行登录。
这个按钮可以正常工作-它重定向到授权服务器,并在成功登录后打开 /Identity/Account/ExternalLogin ,提供填写缺少的用户声明以进行本地注册(特别是电子邮件)的建议。
实际上,首先打开地址/signin-oidc,我相信该处理程序基于接收到的授权代码完成身份验证过程。
然而,我不需要除OpenIDConnect之外的任何其他授权方法。我需要未经授权的用户立即重定向到远程授权服务器。
我如何防止其他登录方法并直接重定向到授权服务器,而不是ASP.NET登录页面?
1个回答

5

然而,我只需要OpenIDConnect授权方法,不需要其他任何授权方式。我需要一个未经授权的用户立即重定向到远程授权服务器。

如何防止其他登录方式并直接重定向到授权服务器,而不是到ASP.NET登录页?

实际上,有一种方法可以直接重定向到授权服务器,而不需要访问任何本地登录页面。

但通常我们仍然需要另一个SignInScheme。如果您查看源代码,您会发现当远程身份验证处理程序成功验证某个用户时,它将会登录该用户

   // ...
   await Context.SignInAsync(SignInScheme, ticketContext.Principal, ticketContext.Properties);
   // ...
例如,如果OAuth2.0认证成功,我们应该为当前用户设置一个cookie或发放JWT令牌
至于你的问题,最简单的方法是在Challenge / Signin中注册一个cookie方案:
services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect("MyOIDC", options =>
    {
        // ...
    }

现在你可以随意使用[Authorize]。 上面的代码对我来说没有问题,即使没有ASP.NET Core Identity[更新]:抱歉,我忘记提到我们必须自定义挑战流程:
  1. 方法1:为Cookie配置一个前向挑战方案:
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>{
        options.ForwardChallenge ="MyOIDC";

    })
    .AddOpenIdConnect("MyOIDC", options =>
    {
         // ....
    }

方法二:手动调用挑战方案:
    public class AccountController : Controller
    {
        public async Task Login(string returnUrl = "/")
        {
            await HttpContext.ChallengeAsync("MyOIDC", new AuthenticationProperties() { RedirectUri = returnUrl });
        }
        
        // if you need sign out the MyOIDC service, you could sign out the user for two schemes as below :
        [Authorize]
        public async Task Logout()
        {
            await HttpContext.SignOutAsync("MyOIDC", new AuthenticationProperties
            {
                RedirectUri = Url.Action("Index", "Home")
            });
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }

之后我被重定向到/Account/Login?ReturnUrl=%2F,但并没有重定向到授权服务。我该如何改变这种行为? - user11114520
@Emanuel 抱歉,我忘了提到我们必须自定义挑战过程。请查看我的更新答案。 - itminus
谢谢,它起作用了!也许您可以解释一下为什么SignInManager.IsSignedIn(User)现在返回false到_LoginPartial.cshtml,即使用户实际上已经被授权并且我可以读取他的声明? - user11114520
@Emanuel SignInManager 是在 ASP.NET Core Identity 中定义的。由于我们从未在此处使用过 ASP.NET Core Identity,因此它肯定不起作用。 - itminus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接