如何在没有 Authorize 属性的情况下在 ASP Core 2 方法中获取用户声明?

How to get user claims inside ASP Core 2 method without Authorize attribute?

我在 API 上有一个可以匿名访问的方法。我想使用资源授权来确定用户是否具有访问权限。如果对象是 "public" 则任何人(包括匿名用户)都可以访问它。如果对象是 "private",则只能由登录用户查看。如果我在方法上有一个授权属性,这个逻辑就可以正常工作,但如果没有,用户即使在登录时也没有声明。

有没有办法在没有 Authorize 属性的方法中获取用户的声明?

方法如下所示:

    [HttpGet]
    [Route("name/{name}")]
    public async Task<IActionResult> Get(string name)
    {
        var activity = Repo.GetCommandLineActivity(name);
        if (activity == null)
        {
            return NotFound();
        }

        var isAuthed = await _authService.AuthorizeAsync(User, activity, new ViewIPublicPrivateRequirement());
        if (isAuthed.Succeeded)
        {
            return Ok(activity);
        }

        return Unauthorized();
    }

简答 - 你不能。

如果仔细检查,您会发现,当您拥有 Authorize 属性时,用户对象的类型为 ClaimsPrincipal,而当您没有它时,它的类型为 WindowsPrincipal.

但您始终可以添加自定义 Authorize 属性或 Custom policy-based authorization,然后检查那里的用户声明并执行您的操作。

即使没有 [Authorize] 属性也可以检索 ClaimsPrincipal,但这确实感觉像是破解,我不推荐它。如果我是你,我会创建两个不同的端点,一个用于 public 访问,另一个用于经过身份验证的用户。

也就是说,检索 ClaimsPrincipal 的方法是调用 AuthenticateAsync 方法。请注意,此代码适用于 ASP.NET Core 2.0,对于 1.1 会略有不同。

修改后的方法如下:

[HttpGet("name/{name}")]
[AllowAnonymous]
public async Task<IActionResult> Get(string name)
{
    var activity = Repo.GetCommandLineActivity(name);
    if (activity == null)
    {
        return NotFound();
    }

    // based on the way your authentication is configured in services.AddAuthentication(),
    // this can be omitted (in which case, the default authenticate scheme will be used) 
    var authenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    var auth  = await HttpContext.AuthenticateAsync(authenticationScheme);
    if (auth.Succeeded)
    {
        // CAUTION: HttpContext.User will STILL be null
        var user = auth.Principal;
        return Ok(activity);
    }

    return Unauthorized();
}

注意:如果省略 [Authorize] 属性(或指定 [AllowAnonymous],则不会设置 HttpContext.User

解决方案实际上非常简单,添加 [AllowAnonymous][Authorize] 就可以了。