Я настроил Овина UseOAuthBearerAuthentication
, чтобы пользователи указывали имя пользователя и пароль и получали токен доступа. После проверки подлинности им необходимо подтвердить себя с помощью 2FA следующим образом:
[Authorize]
[HttpPost]
[Route("tfa/verify")]
public IHttpActionResult VerifyTOTPCode(sds_TOTPCode code) {
using (var session = MiConnectionHelper.CreateSession())
{
Guid loggedOnUserOid = ((ClaimsIdentity) User.Identity).GetUserOid();
MiUser user = MiBusinessObjectHelper.Instance.GetTop1<MiUser>(new BinaryOperator(nameof(MiUser.Oid), loggedOnUserOid),
MiBusinessObjectHelper.Instance.GetDefaultSorting(),
session);
var tfa = new TwoFactorAuth("Test");
if (tfa.VerifyCode(user.Description, code.Code))
{
// TFA not verified yet
if (!user.IsTFAVerified)
{
user.IsTFAVerified = true;
session.CommitChanges();
}
HttpContext.Current.Session["TFAAuthenticated"] = true;
return Ok();
}
return StatusCode(HttpStatusCode.Forbidden);
}
}
Как видите, я устанавливаю HttpContext.Current.Session["TFAAuthenticated"] = true;
, чтобы сохранить, если пользователь также был проверен с использованием 2FA.
Кроме того, у меня есть следующее промежуточное ПО:
namespace MiRestAPI.Middleware
{
public class TwoFactorAuthMiddleware: OwinMiddleware
{
public TwoFactorAuthMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
// TODO: Check type of authentication (Windows Authentication should have TFA disabled)
if (context.Request.User.Identity.IsAuthenticated && !context.Request.Path.Value.Contains("/auth/tfa/"))
{
using (var session = MiConnectionHelper.CreateSession())
{
Guid loggedOnUserOid = ((ClaimsIdentity) context.Request.User.Identity).GetUserOid();
MiUser user = MiBusinessObjectHelper.Instance.GetTop1<MiUser>(new BinaryOperator(nameof(MiUser.Oid), loggedOnUserOid),
MiBusinessObjectHelper.Instance.GetDefaultSorting(),
session);
var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
bool tfaAuthenticated = httpContext.Session["TFAAuthenticated"] as bool? ?? false;
if (user != null && user.Is2FAEnabled && (!user.IsTFAVerified || !tfaAuthenticated))
{
context.Response.StatusCode = 428;
return context.Response.WriteAsync("Two Factor Authentication Required");
}
}
}
return Next.Invoke(context);
}
}
}
Это промежуточное ПО должно проверять, был ли пользователь проверен с использованием 2FA, и если нет, возвращать код состояния ошибки. Проблема в том, что сеанс не сохраняется между запросами, идентифицированными одним и тем же токеном. Я предполагаю, что. NET создает новый сеанс для каждого запроса, даже если они приходят с одинаковым токеном доступа?
Если это так, каким будет решение для сохранения этого состояния между запросами?