I have tried to implement Okta login in my app. I'm running a test app to figure it out before I edit the real app. I load the url and it authenticates through Okta as it should. Then it does to a page saying "Loading..." for a few seconds and then gives an error: enter image description here

本地重定向(RedirectUri)应该重定向到"/".相反,它再次循环回到Login函数.

加入时间:清华2007年01月25日下午3:33

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

namespace TestOktaLogin.Controllers {
    public class LoginController : Controller {
        [HttpGet("Login")]
        public IActionResult Login([FromQuery] string returnUrl) {
            var redirectUri = returnUrl is null ? "/" : "/" + returnUrl;

            if (User.Identity.IsAuthenticated) {
                return LocalRedirect(redirectUri); //It does not return. It just reloads the function.
            }

            return Challenge();
        }

        // This is the method the Logout button should get to when clicked.
        [HttpGet("Logout")]
        public async Task<ActionResult> Logout([FromQuery] string returnUrl) {
            var redirectUri = returnUrl is null ? Url.Content("~/") : "/" + returnUrl;

            if (!User.Identity.IsAuthenticated) {
                return LocalRedirect(redirectUri);
            }

            await HttpContext.SignOutAsync();

            return LocalRedirect(redirectUri);
        }
    }
}

重定向到登录.

using Microsoft.AspNetCore.Components;

namespace TestOktaLogin.Components {
    public partial class RedirectToLogin : ComponentBase {
        [Inject] public NavigationManager Navigation { get; set; }

        protected override async Task OnInitializedAsync() {
            var returnUrl = Navigation.ToBaseRelativePath(Navigation.Uri);

            Navigation.NavigateTo($"Login?returnUrl={returnUrl}", true);
        }
    }
}```




家.razor, which is the default to "/":

@page"/"

@属性[授权]

Hello, world!

欢迎使用您的新apply.`

Program.cs:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using TestOktaLogin.Components;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

builder.Services.AddMvc();

builder.Services.AddAuthentication(authOptions => {
    authOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    authOptions.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    authOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}).AddOpenIdConnect(oidcOptions => {
    oidcOptions.ClientId = builder.Configuration["Okta:ClientId"];
    oidcOptions.ClientSecret = builder.Configuration["Okta:ClientSecret"];
    oidcOptions.CallbackPath = "/authorization-code/callback";
    oidcOptions.Authority = builder.Configuration["Okta:Issuer"];
    oidcOptions.ResponseType = "code";
    oidcOptions.SaveTokens = true;
    oidcOptions.Scope.Add("openid");
    oidcOptions.Scope.Add("profile");
    oidcOptions.TokenValidationParameters.ValidateIssuer = false;
    oidcOptions.TokenValidationParameters.NameClaimType = "name";
}).AddCookie();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment()) {
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.Run();

编辑: 这是我的路由.剃须刀

@using TestOktaLogin.Components.Layout

<CascadingValue Name="AccessToken" Value="AccessToken">
    <CascadingAuthenticationState>
        <Router AppAssembly="@typeof(App).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData=@routeData DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        <RedirectToLogin /> @* Would this cause the problem? *@
                    </NotAuthorized>
                    <Authorizing>
                        Authorizing...
                    </Authorizing>
                </AuthorizeRouteView>
            </Found>
            <NotFound>
                <PageTitle>Not found</PageTitle>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p role="alert">Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    </CascadingAuthenticationState>

</CascadingValue>

@code{
    [Parameter] public string AccessToken { get; set; }
}

这是MainLayout.razor

@inherits LayoutComponentBase

<div>
    <LoginDisplay/>
</div>

@Body

<div id="blazor-error-ui">
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

如果有任何额外的代码我需要上传,让我知道.谢谢你的帮助!

推荐答案

您有以下循环:

User -> Login -> Okta -> LoginController -> LocalRedirect -> Home (Authorized)
  ^                                                                  |
  |__________________________________________________________________|

发生这种循环是因为在LocalRedirect之后,用户被重定向回登录过程,而不是主页.

In the Login action, you are checking if the user is authenticated and then performing a LocalRedirect.
The Challenge method is correctly placed to initiate the authentication process, when the user is not authenticated.

该循环不是从Challenge本身发起的,但如果在用户通过身份验证后可能会发生:它们被重定向回需要身份验证的路由,而Authorize attribute将它们重定向回登录页面,因为它不会将用户识别为已通过身份验证.

亦见"Overview of ASP.NET Core authentication"

在你的LoginController人中发放Challenge分的特定部分:

if (User.Identity.IsAuthenticated) {
    return LocalRedirect(redirectUri); // If authenticated, redirect to the return URL or home
} else {
    return Challenge(); // If not authenticated, initiate the authentication process
}

潜在的问题可能出在LocalRedirect(redirectUri)行上:如果redirectUri不知何故配置错误,并且重定向回一个页面,而该页面最终再次重定向到/Login(就像RedirectToLogin组件可能会做的那样),这将创建一个循环.该循环将继续,直到浏览器因重定向太多而停止它,从而导致您看到的"Too Many Requests"错误.

此外,Program.cs中的中间件可能配置错误,没有正确维护身份验证状态,或者在Home.razor中使用了不正确的Authorize属性使用.

要调试此问题:

  • 在身份验证后,确保redirectUri是有效且可访问的路由.
  • 确认Home页识别身份验证状态,并且不重定向回Login页.
  • 验证Program.cs中的身份验证中间件是否正确配置为可以处理登录后的身份验证状态.
  • 使用日志(log)记录来跟踪重定向流,以查看重定向循环发生的确切位置.

如果这些判断都是正确的,则循环应该被中断,并且用户在身份验证之后应该被正确地重定向到主页.


Make sure your Login action is not being called again after a successful authentication.
That should be done by adjusting the redirectUri logic and making sure the Challenge only occurs when necessary.

那么你的LoginController就是:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

namespace TestOktaLogin.Controllers {
    public class LoginController : Controller {
        [HttpGet("Login")]
        public IActionResult Login([FromQuery] string returnUrl) {
            // Make sure returnUrl is not causing a loop back to this action
            var redirectUri = Url.IsLocalUrl(returnUrl) && !string.IsNullOrEmpty(returnUrl)
                ? returnUrl
                : "/";

            if (User.Identity.IsAuthenticated) {
                // Redirect to the original requested resource or home if authenticated
                return LocalRedirect(redirectUri);
            }

            // Only issue a challenge if the user is not authenticated
            return Challenge();
        }

        // Rest of your code
    }
}

现在,您需要判断以确保returnUrl是本地的,而不是null或空的,以防止重定向到可能导致环路的未经授权的路由.

对于RedirectToLogin组件,请确保仅在用户未经过身份验证的情况下使用它,否则,它也可能导致循环.

您还需要确保正确设置了您的OpenID Connect配置和Home.razor中的Authorize属性用法,以防止未经授权的访问,这可能会导致重定向回登录过程.


the comments中的OP Timothy Waters个确认:

解决办法是把钱改成LoginController.cs元,再加上其他几样东西.

  1. 我从所有东西中go 掉了LoginDisplay,特别是从MainLayout.razor中go 掉了<div> <LoginDisplay/> </div>.
  2. 我把@using Microsoft.AspNetCore.Components.Authorization加到了Routes.razor.

在那之后开始工作.

正确:通过从组件中删除LoginDisplay,您可能已经消除了任何可能导致重定向循环的冲突身份验证逻辑. 添加@using Microsoft.AspNetCore.Components.Authorization允许Blazor组件访问必要的身份验证功能,确保身份验证状态得到正确识别.

这些变化,加上如上所述对LoginController.cs的修改,帮助解决了这个问题.

Csharp相关问答推荐

在ASP.NET中为数据注释 Select 合适的语言

在. NET Core 8 Web API中,当为服务总线使用通用消费者时,如何防止IServiceProvider被释放或空?"

. NET 8使用COM向VB6公开

更新产品但丢失产品ASP.NET Core的形象

使用HttpResponseMessage中的嵌套列表初始化JSON

如何使用NumberFormatInfo

Automapper 12.x将GUID映射到字符串

在两个已具有一对多关系的表之间添加另一个一对多关系

如何在GRPC代码First服务的返回类型上使用多态性?

WPF动态设置弹出窗口水平偏移

C#如何获取字符串中引号之间的文本?

C#使用相同内存的多个数组

如何设置WinForms按钮焦点,使其看起来像是被Tab键插入其中?

无法向Unity注册Microsoft Logger

Cmd中的&ping.end()";有时会失败,而";ping";总是有效

如何使用LINQ在C#中填充列表列表?

游戏对象走向不同的方向

通过mini kube中的远程调试Pod与从emoteProcessPickerScript中解析错误输出的代码错误进行比较

我可以阻止类型上的Object.ToString()吗?

带有类约束的C#泛型