c# - ASP.NET Core Identity 2.0 - 将 401 状态代码返回到 ajax 函数

标签 c# ajax asp.net-core asp.net-core-2.0 asp.net-identity-2

我有一个 ASP.NET Core 应用程序,其中使用 Identity 2.0。我试图在用户未登录时返回 401 状态代码(或在未授权时返回 403),但不同的函数仅返回 302 代码...

我根据我的应用程序需求进行了设置:

  • 个性化的[授权]方法

    [HttpPost]
    [RequiresPermission("Projects.Creation, Projects.Modification")]
    public IActionResult SaveProject(Project prj)
    {
     (...)
    {
    

我的 RequiresPermission 是一个继承 TypeFilterAttribute 的类,并且有一个函数似乎对于设置不同的返回结果很有用:

 public async Task OnResourceExecutionAsync(ResourceExecutingContext context,
                                                   ResourceExecutionDelegate next)
        {
            var principal = new CustomPrincipal(_PermissionProvider, context.HttpContext.User.Identity);
            bool isInOneOfThisRole = false;
            foreach (var item in _requiredPermissions.RequiredPermissions)
            {
                if (principal.IsInRole(item))
                {
                    isInOneOfThisRole = true;
                }
            }

            if (isInOneOfThisRole == false)
            {
                if (principal.Identity.IsAuthenticated)
                {
                    context.Result = new UnauthorizedResult();
                }
                else
                {
                    context.Result = new RedirectResult("~/Connexion/Login");
                }

                await context.Result.ExecuteResultAsync(context);
            }
            else
            {
                await next();
            }
        }
  • 我的启动方法中的不同之处

    services.AddIdentity<Utilisateur, Profil>().AddUserManager<CustomUserManager<Utilisateur>>().AddRoleManager<CustomRoleManager>().AddDefaultTokenProviders();
    services.AddTransient<IUserStore<Utilisateur>, UserStore>();
    services.AddTransient<IRoleStore<Profil>, ProfileStore>();
    services.AddTransient<IPermissionProvider, PermissionProvider>();
    
    services.Configure<IdentityOptions>(options =>
    {
        // Lockout settings
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
        options.Lockout.MaxFailedAccessAttempts = 10;
        options.Lockout.AllowedForNewUsers = true;
        //options.SecurityStampValidationInterval = TimeSpan.FromHours(2);
    });
    
    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        // If the LoginPath isn't set, ASP.NET Core defaults the path to /Account/Login.
        options.LoginPath = new PathString("/Connexion/Login");
        options.LogoutPath = new PathString("/Connexion/SignedOut");
        // If the AccessDeniedPath isn't set, ASP.NET Core defaults the path to /Account/AccessDenied.
        options.AccessDeniedPath = new PathString("/Connexion/AccessDenied");
        options.SlidingExpiration = true;
    });
    

我尝试了很多建议,但似乎没有什么效果:

services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;    
        return Task.CompletedTask;
    };
});

这个解决方案对我来说不是一个好的解决方案,因为它重定向 ajax 和非 ajax 方法,这破坏了我的其他重定向......

我还尝试使用我在网上找到的类来重写 AuthorizeAttribute 类。这个类似乎是我想要的,但它不适用于 ASP.Net Core...

using Microsoft.AspNetCore.Authorization;
using System.Net;

public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        var request = httpContext.Request;
        var response = httpContext.Response;
        var user = httpContext.User;

        if (request.IsAjaxRequest())
        {
            if (user.Identity.IsAuthenticated == false)
                response.StatusCode = (int)HttpStatusCode.Unauthorized;
            else
                response.StatusCode = (int)HttpStatusCode.Forbidden;

            response.SuppressFormsAuthenticationRedirect = true;
            response.End();
        }

        base.HandleUnauthorizedRequest(filterContext);
    }
}

你有办法解决我的问题吗?或者也许我做错了什么。

最佳答案

感谢 Brad,我找到了解决方案,但它太愚蠢了......

我不需要 ApplicationAuthorizeAttribute 类,因为我已经有了 RequiresPermissionAttribute 类。

问题出在我的函数 OnResourceExecutionAsync() 中:

  • 当用户没有权限时,我返回了错误的代码(未经授权而不是禁止结果)
  • 当我的用户未登录时,我将重定向结果返回到我的登录页面,而不是 StatusResult。我将其更改为 UnauthorizedResult()。

更改了我的部分功能:

            if (isInOneOfThisRole == false)
            {
                if (principal.Identity.IsAuthenticated)
                {
                    context.Result = new ForbidResult();
                }
                else
                {
                    context.Result = new UnauthorizedResult();
                }

                await context.Result.ExecuteResultAsync(context);
            }
            else
            {
                await next();
            }

我的 ajax 中已经有一个函数来捕获不同的状态代码:

$(document).ajaxError(function (xhr, props) {
    if (props.status == 403) {
        window.location = window.location.protocol + '//' + window.location.host + "/Connexion/AccessDenied";
    } else if (props.status == 401) {
        window.location = window.location.protocol + '//' + window.location.host + "/Connexion/Login";
    }
});

一切都运行良好!

关于c# - ASP.NET Core Identity 2.0 - 将 401 状态代码返回到 ajax 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52197786/

相关文章:

c# - 使用 internal 作为访问修饰符时,程序集包括什么?

asp.net-core - 为什么.NET Core构建生成EXE文件但不生成dll文件?

c# - 为什么多次调用 app.UseEndpoints(..) 时中间件不执行?

visual-studio - 异常 : In process hosting is not supported for AspNetCoreModule. 将 AspNetCoreModule 更改为至少 AspNetCoreModuleV2

C# Serilog 仅在错误后收到电子邮件

c# - UTF-8 不适用于将 byte[] 转换为字符串

c# - 在 visual studio c++ 中绘制实时图形

javascript - 如何将值从 MVC ActionResult 传递到 AJAX 成功回调函数?

javascript - 在不使用操作监听器的情况下使用 JSF 2.0 执行 AJAX

javascript - 浏览器如何存储 Etag 以及存储多长时间?