如何在没有 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]
就可以了。
我在 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]
就可以了。