認証と承認にJWTを使用するCore 2.0 Web APIプロジェクトを作成しています。保護したいコントローラーメソッドはすべてAuthorize
属性で装飾されています。
これは機能しています。 BearerヘッダーでJWTを渡すと、200を取得します。JWTを渡せない場合は、401を取得します。すべて動作しています。私のJWTでは、認証時に「UserId」フィールドにユーザーIDを保存しました。
var claimsdata = new[] {
new Claim("UserId", user.Id.ToString()),
次に、拡張メソッドがあります:
public static string GetUserId(this IPrincipal user)
{
if (user == null)
return string.Empty;
var identity = (ClaimsIdentity)user.Identity;
IEnumerable<Claim> claims = identity.Claims;
return claims.FirstOrDefault(s => s.Type == "UserId")?.Value;
}
私のコントローラーメソッドでは、「承認」を使用して、ユーザーのIDが必要になることがよくあります。そこで、GetUserIdメソッドを呼び出します。これは機能します。ただし、これがトークンからIDを取得する最善の方法であるかどうかはわかりません。
int.TryParse(User.GetUserId(), out _userId);
すべてのコントローラーでそのコードを使用する必要があります。私はそれが間違っていると思うので、コンストラクタでそれを行うことはできません。
私はここで正しいことをしていますか?
ControllerBase
には、User
のタイプであるClaimsPrincipal
プロパティが含まれています
User.Claims
でユーザーのクレームにアクセスできます。IPrincipal
は必要ありません。
GetUserId
メソッドをprotected
として含むベースコントローラを作成します。
public abstract class BaseController : Controller
{
protected int GetUserId()
{
return int.Parse(this.User.Claims.First(i => i.Type == "UserId").Value);
}
}
そして、すべてのコントローラがこれから継承し、すべてのコントローラがUserId
にアクセスできるようになりました
最初に、IUserProvider
インターフェースをIHttpContextAccessor
インジェクションで作成して、単体テストでこれらのインターフェースのモックを作成します。
public interface IUserProvider
{
string GetUserId();
}
実装より
public class UserProvider : IUserProvider
{
private readonly IHttpContextAccessor _context;
public UserProvider (IHttpContextAccessor context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public string GetUserId()
{
return _context.HttpContext.User.Claims
.First(i => i.Type == ClaimTypes.NameIdentifier).Value;
}
}
したがって、継承なしでコントローラーでインターフェースIUserProvider
を使用できます
[Authorize]
[ApiController]
public class MyController : ControllerBase
{
private readonly IUserProvider _userProvider;
public MyController(IUserProvider userProvider)
{
_userProvider = userProvider ?? throw new ArgumentNullException(nameof(userProvider ));
}
[HttpGet]
[Route("api/My/Something")]
public async Task<ActionResult> GetSomething()
{
try
{
var userId= _userProvider.GetUserId();
}
}
}
また使用できます
延長方法
このような
public static long GetUserID(this ClaimsPrincipal User)
{
return long.Parse(User.Claims.First(i => i.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value);
}
このようにコントローラに実装します
[HttpDelete("DeleteAddress")]
public async Task<IActionResult> DeleteAddress([FromQuery] long AddressID)
{
try
{
long userID = this.User.GetUserID();
await _addressService.Delete(userID, AddressID);
return Ok();
}
catch (Exception err)
{
return Conflict(err.Message);
}
}
お役に立てば幸いです