В моем приложении webapi, созданном из шаблона в VS2013, я добавил собственный класс OAuthBearerAuthenticationProvider в файл Startup.Auth.cs:
public class CustomBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task ValidateIdentity(OAuthValidateIdentityContext context)
{
UserManager<ApplicationUser> userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = userManager.FindById(context.Ticket.Identity.GetUserId());
var claims = context.Ticket.Identity.Claims;
if (claims.FirstOrDefault(claim => claim.Type == "AspNet.Identity.SecurityStamp") == null
|| claims.Any(claim => claim.Type == "AspNet.Identity.SecurityStamp"
&& !claim.Value.Equals(user.SecurityStamp)))
{
context.Rejected();
}
return Task.FromResult<object>(null);
}
}
Также я добавил переменную:
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
А в методе ConfigureAuth (приложение IAppBuilder) я добавил следующие строки кода для использования настраиваемого класса OAuthBearerAuthenticationProvider:
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
OAuthBearerOptions.AccessTokenFormat = OAuthOptions.AccessTokenFormat;
OAuthBearerOptions.AccessTokenProvider = OAuthOptions.AccessTokenProvider;
OAuthBearerOptions.AuthenticationMode = OAuthOptions.AuthenticationMode;
OAuthBearerOptions.AuthenticationType = OAuthOptions.AuthenticationType;
OAuthBearerOptions.Description = OAuthOptions.Description;
OAuthBearerOptions.Provider = new CustomBearerAuthenticationProvider();
OAuthBearerOptions.SystemClock = OAuthOptions.SystemClock;
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
Все изменения, которые я внес для реализации собственной логики проверки токена на предъявителя. По какой-то причине проверка SecurityStamp не реализована в приложении Webapi, созданном из шаблона в VS 2013. Я думал, что это должно было быть сделано по умолчанию.
Чтобы проверить концепцию проверки SecurityStamp, я изменил SecurityStamp в базе данных и после этого вызвал некоторый метод webapi с клиента, используя старый токен-носитель, то есть содержащий старое утверждение SecurityStamp. Обратите внимание, что мой контроллер webapi помечен атрибутом [Authorize]. После этого был вызван метод ValidateIdentity (OAuthValidateIdentityContext context) и была выполнена строка context.Rejected (), и я ожидал, что после этого метод webapi не должен вызываться, а ответ 401 Unauthorized должен быть отправлен обратно клиенту.
Но ничего этого не произошло. Метод Webapi действительно был вызван, и клиент успешно получил конфиденциальные данные с сервера, тогда как не должен, потому что старый токен-носитель, который клиент отправил на сервер для аутентификации и авторизации, не должен быть действительным после изменения пароля.
Я подумал, что если context.Rejected () был вызван в методе ValidateIdentity, любой [Authorize] декорированный метод webapi не должен вызываться, и клиент должен получить что-то вроде 401 Unauthorized response.
Я все неправильно понимаю? Если можно, кто-нибудь может объяснить, как это работает, пожалуйста? Почему после вызова context.Rejected () вызывается метод webapi аннотированного контроллера [Authorize], который успешно возвращает конфиденциальные данные? Почему вместо этого не был отправлен ответ 401 Unauthorized? Как достичь цели, заключающейся в том, что ответ 401 Unauthorized должен быть отправлен обратно клиенту, когда запрос SecurityStamp не такой, как в базе данных в настоящее время?