Asp.net core AuthenticationHandler错误AuthenticationScheme:禁止承载
我正在使用ASP.NET核心制作一个小型服务。我现在面临的第一件复杂的事情是对系统中的用户进行身份验证 让我介绍一下我的身份验证流程: +)客户端->调用(api/帐户/授权)->系统检查客户端是否有效->在客户端有效时将令牌发送回客户端 +)客户端->使用获得的令牌->请求api/account/filter->服务验证令牌并将信息返回 我已经阅读了一些关于JWT的教程,但是回复中没有包含我需要的足够信息我想要:Asp.net core AuthenticationHandler错误AuthenticationScheme:禁止承载,asp.net-core,asp.net-core-webapi,asp.net-core-middleware,Asp.net Core,Asp.net Core Webapi,Asp.net Core Middleware,我正在使用ASP.NET核心制作一个小型服务。我现在面临的第一件复杂的事情是对系统中的用户进行身份验证 让我介绍一下我的身份验证流程: +)客户端->调用(api/帐户/授权)->系统检查客户端是否有效->在客户端有效时将令牌发送回客户端 +)客户端->使用获得的令牌->请求api/account/filter->服务验证令牌并将信息返回 我已经阅读了一些关于JWT的教程,但是回复中没有包含我需要的足够信息我想要: 抛出401和一条消息描述了状态代码,即:“帐户已禁用”、“帐户待决”、“帐户权
- 抛出401和一条消息描述了状态代码,即:“帐户已禁用”、“帐户待决”、“帐户权限不足”、。。。不仅仅是401
public class BearerAuthenticationHandler : AuthenticationHandler<BearerAuthenticationOption>
{
#region Properties
/// <summary>
/// Inject dependency service into the handler.
/// </summary>
private readonly JwtTokenSetting _encryptionSetting;
/// <summary>
/// Inject dependency service into the handler.
/// </summary>
private readonly IEncryptionService _encryptionService;
/// <summary>
/// Inject time service to handler.
/// </summary>
private readonly ITimeService _timeService;
private readonly IRepositoryAccount _repositoryAccount;
#endregion
#region Constructors
/// <summary>
/// Initialize an instance of handler with specific dependency injections.
/// </summary>
/// <param name="encryptionSetting"></param>
/// <param name="encryptionService"></param>
/// <param name="timeService"></param>
/// <param name="repositoryAccount"></param>
public BearerAuthenticationHandler(JwtTokenSetting encryptionSetting, IEncryptionService encryptionService, ITimeService timeService, IRepositoryAccount repositoryAccount)
{
_encryptionSetting = encryptionSetting;
_encryptionService = encryptionService;
_timeService = timeService;
_repositoryAccount = repositoryAccount;
}
#endregion
#region Methods
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
#region Token analyzation
// Find the authorization key in request.
var authorizationKey =
Request.Headers.Keys.FirstOrDefault(x => x.Equals("authorization", StringComparison.OrdinalIgnoreCase));
// Authorization key is not found in the request.
if (string.IsNullOrWhiteSpace(authorizationKey))
return AuthenticateResult.Fail("No authorization is found in request header.");
// Find the token in Authorization.
var authorizationValue = Request.Headers[authorizationKey].ToString();
// Authentication scheme prefix.
var authenticationScheme = $"{Options.AuthenticationScheme} ";
// No token has been specified.
if (string.IsNullOrWhiteSpace(authorizationValue) || !authorizationValue.StartsWith(authenticationScheme, StringComparison.OrdinalIgnoreCase))
return AuthenticateResult.Fail("No bearer token is found in request header.");
// Cut the string to obtain bearer token.
var accessToken = authorizationValue.Substring(authenticationScheme.Length);
#endregion
#region Token validation
// Decrypt the token.
var tokenDetailViewModel = _encryptionService.Decrypt<TokenDetailViewModel>(accessToken, _encryptionSetting.Key);
// No detail has been found.
if (tokenDetailViewModel == null)
{
InitializeHttpResponse(Response, HttpStatusCode.Unauthorized, new HttpResponseViewModel
{
Message = "TOKEN_INVALID"
});
return AuthenticateResult.Fail("Token is invalid");
}
// Find the current unix time on server.
var unixTime = _timeService.UtcToUnix(DateTime.UtcNow);
// Token is expired.
if (unixTime > tokenDetailViewModel.Expire)
{
InitializeHttpResponse(Response, HttpStatusCode.Unauthorized, new HttpResponseViewModel
{
Message = "TOKEN_EXPIRED"
});
return AuthenticateResult.Fail("Token is expired");
}
// Account filter construction.
var filterAccountViewModel = new FilterAccountViewModel
{
Email = tokenDetailViewModel.Email,
EmailComparison = TextComparision.Equal,
Password = tokenDetailViewModel.Password,
PasswordComparision = TextComparision.EqualIgnoreCase,
Statuses = new[] { AccountStatus.Active }
};
// Find the first condition statisfied account in the database.
var account = await _repositoryAccount.FindAccountAsync(filterAccountViewModel);
// Account cannot be found in the database.
if (account == null)
{
InitializeHttpResponse(Response, HttpStatusCode.Unauthorized, new HttpResponseViewModel
{
Message = "ACCOUNT_INVALID"
});
return AuthenticateResult.Fail("Account is invalid");
}
#endregion
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(new Claim(nameof(JwtClaim.Email), account.Email));
claimsIdentity.AddClaim(new Claim(nameof(JwtClaim.Status), nameof(account.Status)));
// Update user into context.
var claimPrincipal = new ClaimsPrincipal(claimsIdentity);
// Initialize an authentication ticket.
var authenticationTicket = new AuthenticationTicket(claimPrincipal, new AuthenticationProperties
{
AllowRefresh = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(30),
IsPersistent = true,
IssuedUtc = DateTime.UtcNow
}, "Bearer");
return AuthenticateResult.Success(authenticationTicket);
}
/// <summary>
/// Initialize an application/json response.
/// </summary>
/// <param name="httpResponse"></param>
/// <param name="httpStatusCode"></param>
/// <param name="httpResponseViewModel"></param>
private void InitializeHttpResponse(HttpResponse httpResponse, HttpStatusCode httpStatusCode, HttpResponseViewModel httpResponseViewModel)
{
// Response must be always application/json.
httpResponse.ContentType = "application/json";
httpResponse.StatusCode = (int)httpStatusCode;
if (httpResponseViewModel == null)
return;
using (var streamWriter = new StreamWriter(httpResponse.Body))
{
streamWriter.AutoFlush = true;
streamWriter.WriteLineAsync(JsonConvert.SerializeObject(httpResponseViewModel));
}
}
#endregion
}
公共类BeareAuthenticationHandler:AuthenticationHandler
{
#区域属性
///
///将依赖项服务注入处理程序。
///
私有只读JwtTokenSetting _encryptionSetting;
///
///将依赖项服务注入处理程序。
///
专用只读电子选择服务(U encryptionService);;
///
///向处理程序注入时间服务。
///
私有只读ITimeService\u timeService;
私人只读IRepositoryAccount\u repositoryAccount;
#端区
#区域构造函数
///
///使用特定依赖项注入初始化处理程序的实例。
///
///
///
///
///
public BeareAuthenticationHandler(JwtTokenSetting encryptionSetting、encryptionService encryptionService、ITimeService timeService、IRepositoryAccount repositoryAccount)
{
_encryptionSetting=加密设置;
_encryptionService=加密服务;
_时间服务=时间服务;
_repositoryAccount=repositoryAccount;
}
#端区
#区域方法
受保护的重写异步任务handleAuthenticateAync()
{
#区域标记分析
//在请求中查找授权密钥。
var授权密钥=
Request.Headers.Keys.FirstOrDefault(x=>x.Equals(“授权”,StringComparison.OrdinalIgnoreCase));
//在请求中找不到授权密钥。
if(string.IsNullOrWhiteSpace(authorizationKey))
返回AuthenticateResult.Fail(“在请求头中找不到授权”);
//在授权中查找令牌。
var authorizationValue=Request.Headers[authorizationKey].ToString();
//身份验证方案前缀。
var authenticationScheme=$“{Options.authenticationScheme}”;
//未指定任何令牌。
if(string.IsNullOrWhiteSpace(authorizationValue)| |!authorizationValue.StartsWith(authenticationScheme,StringComparison.OrdinalIgnoreCase))
返回AuthenticateResult.Fail(“在请求头中找不到承载令牌”);
//剪切字符串以获取承载令牌。
var accessToken=authorizationValue.Substring(authenticationScheme.Length);
#端区
#区域令牌验证
//解密令牌。
var tokenDetailViewModel=\u encryptionService.Decrypt(accessToken,\u encryptionset.Key);
//没有找到任何细节。
if(tokenDetailViewModel==null)
{
初始化HttpResponse(响应,HttpStatusCode.Unauthorized,新的HttpResponseeviewModel
{
Message=“TOKEN\u无效”
});
返回AuthenticateResult.Fail(“令牌无效”);
}
//在服务器上查找当前unix时间。
var unixTime=\u timeService.UtcToUnix(DateTime.UtcNow);
//令牌已过期。
if(unixTime>tokenDetailViewModel.Expire)
{
初始化HttpResponse(响应,HttpStatusCode.Unauthorized,新的HttpResponseeviewModel
{
Message=“令牌\u已过期”
});
返回AuthenticateResult.Fail(“令牌已过期”);
}
//帐户筛选器构造。
var filterAccountViewModel=新的filterAccountViewModel
{
Email=tokenDetailViewModel.Email,
EmailComparison=textComparison.Equal,
Password=tokenDetailViewModel.Password,
passwordcomparison=textcomarison.EqualIgnoreCase,
status=new[]{AccountStatus.Active}
};
//在数据库中查找第一个条件statisfied帐户。
var account=await_repositoryAccount.FindAccountAsync(filterAccountViewModel);
//在数据库中找不到帐户。
如果(帐户==null)
{
初始化HttpResponse(响应,HttpStatusCode.Unauthorized,新的HttpResponseeviewModel
{
Message=“帐户\u无效”
});
返回AuthenticateResult.Fail(“帐户无效”);
}
#端区
var claimsIdentity=新的claimsIdentity();
claimsIdentity.AddClaim(新的索赔(nameof(JwtClaim.Email)、account.Email));
claimsIdentity.AddClaim(新的索赔(nameof(JwtClaim.Status)、nameof(account.Status));
//将用户更新到上下文中。
var claimPrincipal=新的ClaimsPrincipal(索赔实体);
//初始化身份验证票证。
var authenticationTicket=新的authenticationTicket(claimPrincipal,新的AuthenticationProperties
{
AllowRefresh=true,
ExpiresUtc=DateTime.UtcNow.AddMinutes(30),
ispersist=true,
IssuedUtc=DateTime.UtcNow
}“持票人”);
返回AuthenticateResult.Success(aut
[Route("api/[controller]")]
public class AccountController : Controller
{
private readonly IRepositoryAccount _repositoryAccount;
private readonly IEncryptionService _encryptionService;
private readonly ITimeService _timeService;
private readonly JwtTokenSetting _jwtTokenSetting;
public AccountController(IRepositoryAccount repositoryAccount, IEncryptionService encryptionService, ITimeService timeService,
IOptions<JwtTokenSetting> jwtTokenSetting)
{
_repositoryAccount = repositoryAccount;
_encryptionService = encryptionService;
_timeService = timeService;
_jwtTokenSetting = jwtTokenSetting.Value;
}
[HttpPost("authorize")]
[AllowAnonymous]
public async Task<IActionResult> Authorize([FromBody] LoginViewModel loginViewModel)
{
// Find the encrypted password of login information.
var filterAccountViewModel = new FilterAccountViewModel();
filterAccountViewModel.Email = loginViewModel.Email;
filterAccountViewModel.EmailComparison = TextComparision.Equal;
filterAccountViewModel.Password = _encryptionService.FindEncryptPassword(loginViewModel.Password);
filterAccountViewModel.PasswordComparision = TextComparision.EqualIgnoreCase;
filterAccountViewModel.Statuses = new[] {AccountStatus.Active};
// Initialize HttpResponseViewModel.
var httpResponseViewModel = new HttpResponseViewModel();
// Find the account.
var account = await _repositoryAccount.FindAccountAsync(filterAccountViewModel);
// Account is not found.
if (account == null)
{
Response.ContentType = "application/json";
using (var streamWriter = new StreamWriter(Response.Body))
{
httpResponseViewModel.Message = "ACCOUNT_INVALID";
await streamWriter.WriteLineAsync(JsonConvert.SerializeObject(httpResponseViewModel));
}
return new UnauthorizedResult();
}
// Initialize token detail.
var tokenDetailViewModel = new TokenDetailViewModel
{
Email = loginViewModel.Email,
Password = filterAccountViewModel.Password,
Expire = _timeService.UtcToUnix(DateTime.UtcNow.AddSeconds(_jwtTokenSetting.Expire))
};
// Initialize token information and throw to client for their future use.
var tokenGeneralViewModel = new TokenGeneralViewModel
{
AccessToken = _encryptionService.Encrypt(tokenDetailViewModel, _jwtTokenSetting.Key),
Expire = _jwtTokenSetting.Expire
};
return Ok(tokenGeneralViewModel);
}
[HttpPost("filter")]
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
public IEnumerable<string> FindAllAccounts()
{
Response.StatusCode = (int)HttpStatusCode.Accepted;
return new[] { "1", "2", "3", "4" };
}
}
public class CheckUserRequirement : IAuthorizationRequirement
{
}
public class CheckUserAuthorizationHandler : AuthorizationHandler<CheckUserRequirement>
{
private readonly IHttpContextAccessor _accessor;
public SimpleAuthorizationHandler(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, SimpleRequirement requirement)
{
if(account.isDisabled)
{
_accessor.HttpContext.Response.Headers.Add("error_code", "ACCOUNT_DISABLED");
}
//...
context.Succeed(requirement);
}
}
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IAuthorizationHandler, CheckUserAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("CheckUser", policy => { policy.AddRequirements(new CheckUserRequirement()); });
});
[Authorize(Policy = "CheckUser")]
public class SomeController