You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure App Service访问视图报ERR_TOO_MANY_REDIRECTS,本地VS运行正常

问题排查与解决方案

问题背景

使用Visual Studio 2022 + ASP.NET Core 6 + jQuery v3.6.0开发的应用,本地运行正常,但部署到Azure App Service后访问UserList视图时出现ERR_TOO_MANY_REDIRECTS错误,已清除Cookie但无效。

相关代码如下:

导航链接

<li class="nav-item">
    <a class="dropdown-item" asp-area="" asp-controller="UserList" asp-action="UserList">User List</a>
</li>

控制器代码

public async Task<IActionResult> UserList()
 {
     List<UserListViewModel> users = await _userListControllerHelper.MapToViewModel(_context);
     return View(users);
 }

MapToViewModel方法代码

public async Task<List<UserListViewModel>> MapToViewModel(ApplicationDbContext context)
{
    if (context == null) throw new ArgumentNullException(nameof(context));
     
    List<UserListViewModel> model = new List<UserListViewModel>();

    foreach (var user in context.Users)
    {
        var userDetails = new UserListViewModel();

        userDetails.Username = user.UserName ?? string.Empty;

        var roles = await _userManager.GetRolesAsync(user);

        foreach (var role in roles)
        {
            userDetails.Role += role;
        }

        userDetails.Email = user.Email ?? string.Empty;

        IEnumerable<UsersHospital> usersHospitals = _usersHosptialRepository.GetHospitalIdsFromUserId(user.Id);

        userDetails.UsersHospitalId = usersHospitals is not null ? usersHospitals.FirstOrDefault().id : 0;

        userDetails.Hospital = usersHospitals is not null ? _lookupRepository.EnabledHospitals().FirstOrDefault(x => x.HospitalId == usersHospitals.FirstOrDefault().HospitalId).Hospital : string.Empty;

        userDetails.HasEmailBeenConfirmed = user.EmailConfirmed;

        userDetails.IsLockedOut = user.LockoutEnabled && (user.LockoutEnd is not null && user.LockoutEnd > DateTime.Now);

        model.Add(userDetails);
      
    }

    return model.ToList();
}

视图代码

@model IEnumerable<UserListViewModel>
@section breadcrumb{
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb">
            <li class="breadcrumb-item active" aria-current="page">User List</li>
        </ol>
    </nav>
}

@if (TempData["AlertMessage"] != null)
{
    <div class="alert alert-message alert-success">
        @TempData["alertMessage"]
    </div>
}


<div class="row">
    <div class="card col-md-12 border-0">
        <div class="card-body align-content-center">
            <a class="btn btn-primary btn-block" asp-area="Identity" asp-page="/Account/Register">Register New User</a>
        </div>
     </div>
 </div>

<div class="row mb-5">
    <div class="card-deck col-md-12 overflow-auto">
        <div class="card col-md-12 border p-0">
            <div class="card-header">
                <b>List of Active Users</b>
            </div>
            <div class="UsersList card-body align-content-center">                
                <div class="row p-1 border-1 border-bottom border-top flex-container">
                    <div class="col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end"><b>Username</b></div>
                    <div class="col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end"><b>User Email</b></div>
                    <div class="col-xxl-1 col-xl-1 col-lg-1 col-md-1 border-1 border-end"><b>User Email Confirmed</b></div>
                    <div class="col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end"><b>User Role</b></div>
                    <div class="col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end"><b>User Location</b></div>
                    <div class="col-xxl-3 col-xl-3 col-lg-3 col-md-3"><b>Actions</b></div>
                 </div>

                @if (Model != null)
                {
                    @foreach (var item in Model)
                    {
                        @if (!item.IsLockedOut) 
                        {
                            <div class="row p-1 border-1 border-bottom flex-container card-deck">
                                <div class="card col-xxl-2 col-xl-2 col-lg-2 col-md-2 col-sm-2 border-1 border-end">@item.Username</div>
                                <div class="card col-xxl-2 col-xl-2 col-lg-2 col-md-2 col-sm-2 border-1 border-end">@item.Email</div>
                                <div class="card col-xxl-1 col-xl-1 col-lg-1 col-md-1 border-1 border-end">
                                    @item.HasEmailBeenConfirmed
                                    @if (!item.HasEmailBeenConfirmed)
                                    {
                                        <br />
                                        <a asp-controller="UserList" asp-action="ResendConfirmationEmail" class="btn btn-primary btn-block" asp-route-useremail="@item.Email" asp-route-returnUrl="@Url.Action("UserList", "UserList", new { area = "" })">
                                            Resend
                                        </a>
                                    }
                                </div>
                                <div class="card col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end">@Html.DisplayFor(modelItem => item.Role)</div>
                                <div class="card col-xxl-2 col-xl-2 col-lg-2 col-md-2 border-1 border-end">@Html.DisplayFor(modelItem => item.Hospital)</div>
                                <div class = "col-xxl-3 col-xl-3 col-lg-3 col-md-3">
                                    <a asp-controller="UserList" method="get" asp-action="UserEdit" asp-route-userEmail="@item.Email" class="btn btn-primary btn-block">
                                        Edit User
                                    </a>
                                    <button class="lockUnlockOrDeleteUser btn btn-primary btn-block" data-id="@item.Email" data-type="lock">
                                        Lock User
                                    </button>
                                    <button class="lockUnlockOrDeleteUser btn btn-danger btn-block" data-id="@item.Email" data-type="delete">
                                        Delete User
                                    </button>
                                </div>
                            </div>
                        }
                    }
                }
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="card-deck col-md-12 overflow-auto">
        <div class="card col-md-12 border p-0">
            <div class="card-header">
                <b>List of Locked Out Users</b>
            </div>
            <div class="UsersList card-body align-content-center">

                <div class="row p-1 border-1 border-bottom border-top flex-container">
                    <div class="col-xxl col-xl col-lg col-md border-1 border-end"><b>Username</b></div>
                    <div class="col-xxl col-xl col-lg col-md border-1 border-end"><b>User Role</b></div>
                    <div class="col-xxl col-xl col-lg col-md border-1 border-end"><b>User Email</b></div>
                    <div class="col-xxl col-xl col-lg col-md border-1 border-end"><b>User Location</b></div>
                    <div class="col-xxl-3 col-xl-3 col-lg-3 col-md-3"><b>Actions</b></div>
                </div>

                @if (Model != null)
                {
                    @foreach (var item in Model)
                    {
                        @if (item.IsLockedOut)
                        {
                        <div class="row p-1 border-1 border-bottom flex-container">
                            <div class="col-xxl col-xl col-lg col-md border-1 border-end">@item.Username</div>
                            <div class="col-xxl col-xl col-lg col-md border-1 border-end">@item.Role</div>
                            <div class="col-xxl col-xl col-lg col-md border-1 border-end">@item.Email</div>
                            <div class="col-xxl col-xl col-lg col-md border-1 border-end">@item.Hospital</div>
                            <div class="col-xxl-3 col-xl-3 col-lg-3 col-md-3">
                                <button class="lockUnlockOrDeleteUser btn btn-primary btn-block" data-id="@item.Email" data-type="unlock">
                                    Unlock User
                                </button>
                                <button class="lockUnlockOrDeleteUser btn btn-danger btn-block" data-id="@item.Email" data-type="delete">
                                    Delete User
                                </button>
                            </div>
                        </div>

                        }
                    }
                }
            </div>
        </div>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

<script>

    $(document).on('click', '.lockUnlockOrDeleteUser', (event) => {
        event.preventDefault();
        if (confirm("Are you sure you want to " + event.target.dataset.type + " this user?: " + event.target.dataset.id)) {
            $.ajax({
                url: '@Url.Action("LockUnlockOrDeleteUser", "UserList")',
                type: 'POST',
                data: { userEmail: event.target.dataset.id, type: event.target.dataset.type },
            })
            .done(function (response) {
                switch (response.succeeded) {
                    case false:
                                alert("Failed to " + event.target.dataset.type + " user, please contact FNSD administration for help.");
                        break;
                    case true:
                                alert("User successfully " + event.target.dataset.type + "ed");
                                var urlToRedirect = '@Url.Action("userlist", "userlist")';
                                window.location.href = urlToRedirect;
                        break;
                    default:
                        alert(JSON.stringify(response) + ": Please contact FNSD administration for help.");
                }
            })
            .fail(function (jqXHR, textStatus, errorThrown) {
                alert("AJAX request failed: " + errorThrown + ": Please contact FNSD administration for help.");
            });
        };
    });
</script>
}

排查方向与解决方案

1. 身份验证/授权配置冲突

  • 检查Azure App Service的身份验证设置:若启用了App Service Authentication(Easy Auth),可能和应用内的ASP.NET Core身份验证规则冲突,导致循环重定向。可暂时关闭Easy Auth测试,若问题解决则需调整两者配置,确保权限规则一致。
  • 验证[Authorize]特性配置:确认当前用户拥有访问UserList的权限,若权限不足,应用可能持续重定向到登录页,形成循环。需检查Azure环境中用户角色是否正确同步。

2. HTTPS重定向规则问题

  • 检查Program.cs中的HTTPS重定向代码:
    app.UseHttpsRedirection();
    
    Azure App Service默认处理HTTPS,但应用内重定向规则可能和Azure配置冲突。可在Azure门户应用服务 > 配置 > 常规设置中开启HTTPS强制,同时调整应用内配置:
    app.UseHttpsRedirection(new HttpsRedirectionOptions
    {
        RedirectStatusCode = StatusCodes.Status307TemporaryRedirect
    });
    

3. 路由与URL大小写问题

  • 修正视图中AJAX回调的重定向URL:Azure环境区分大小写,将@Url.Action("userlist", "userlist")改为@Url.Action("UserList", "UserList"),和控制器/Action名称保持一致。
  • 检查Program.cs中的路由规则:确认无重复路由指向UserList Action,避免路由解析导致的重定向循环。

4. 代码潜在异常未处理

  • 修复MapToViewModel中的空值引用风险:
    var firstHospital = usersHospitals?.FirstOrDefault();
    userDetails.UsersHospitalId = firstHospital != null ? firstHospital.id : 0;
    userDetails.Hospital = firstHospital != null ? _lookupRepository.EnabledHospitals().FirstOrDefault(x => x.HospitalId == firstHospital.HospitalId)?.Hospital ?? string.Empty : string.Empty;
    
    未处理的异常可能被全局中间件重定向,引发循环。

5. 缓存与Cookie配置

  • 关闭Azure App Service的ARR缓存:在门户应用服务 > 配置 > 缓存中关闭缓存测试。
  • 检查身份验证Cookie的域配置:确保Cookie域设置适配Azure环境,避免因Cookie无法传递导致的持续登录重定向。

内容的提问来源于stack exchange,提问作者KevBarri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:03:11