2014-12-08 4 views
17

Я создаю веб-api, используя ASP.NET WebApi 2, используя аутентификацию с претензиями, и мои пользователи могут иметь очень большое количество претензий. При большом количестве претензий токен-носитель быстро растет очень быстро, поэтому я пытаюсь найти способ вернуть гораздо более короткий токен-носитель.Работа с длинными токенами-носителями из webapi путем предоставления суррогатного токена

До сих пор я обнаружил, что я могу предоставить IAuthenticationTokenProvider к опциям OAuth OAuthAuthorizationServerOptions.AccessTokenProvider недвижимость:

OAuthOptions = new OAuthAuthorizationServerOptions 
{ 
    TokenEndpointPath = new PathString("/Token"), 
    Provider = new ApplicationOAuthProvider(PublicClientId), 
    AccessTokenExpireTimeSpan = TimeSpan.FromHours(12), 
    AccessTokenProvider = new GuidProvider() // <-- here 
}; 

И это дает мне шанс перехватить AuthenticationTicket и спрятать его подальше, заменив его чем-то более простым - в моем примере ниже хэшированного руководства. (Примечание: На данный момент этот класс просто держит ConcurrentDictionary<string,AuthenticationTicket> с моих сессий - в реальном примере я намерен хранить сессии в некоторой постоянной памяти)

public class GuidProvider : IAuthenticationTokenProvider 
{ 
    private static ConcurrentDictionary<string, AuthenticationTicket> tokens 
     = new ConcurrentDictionary<string, AuthenticationTicket>(); 

    public void Create(AuthenticationTokenCreateContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    public async System.Threading.Tasks.Task CreateAsync(AuthenticationTokenCreateContext context) 
    { 
     var guid = Guid.NewGuid().ToString(); 

     var ticket = Crypto.Hash(guid); 

     tokens.TryAdd(ticket, context.Ticket); 

     context.SetToken(ticket); 
    } 

    public void Receive(AuthenticationTokenReceiveContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    public async System.Threading.Tasks.Task ReceiveAsync(AuthenticationTokenReceiveContext context) 
    { 
     AuthenticationTicket ticket; 

     if (tokens.TryGetValue(context.Token, out ticket)) 
     { 
      if (ticket.Properties.ExpiresUtc.Value < DateTime.UtcNow) 
      { 
       tokens.TryRemove(context.Token, out ticket); 
      } 
      context.SetTicket(ticket); 
     } 
    } 
} 

Так мои вопросы:

  • Является ли это подходящим (и безопасным!) Способом предоставления суррогатного ключа вместо моего долгожданного токена?
  • Может быть, лучше или проще, где я должен делать это в стеке webapi/OAuth?

Другого дело, следует отметить, что я намерен поддерживать токены обновления, а на самом деле выше пример был разобран из примеров, которые используют этот вид механизма маркеров Refresh - за исключением маркеров обновления они кажутся одного -use, поэтому метод ReceiveAsync обычно всегда удаляет токен обновления, поставляемый с ConcurrentDictionary, я не совсем уверен, что понимаю почему?

+0

Этот подход прекрасен, если ваш клиент повторно отправит это разрешение, чтобы вернуть токен доступа, если вы используете его, чтобы обращаться с токенами доступа, которые в OAuth2 будут самолетом, не будет правильным выбором. – Saravanan

+0

Поскольку авторизация может быть изолирована от клиентское приложение, и вы не можете вывести иск из суррогатного токена. – Saravanan

+0

@jamiec мой ответ, используя JWT, помог вам сократить ваш токен доступа, полный претензий? –

ответ

7

Я не рекомендую это делать, потому что вы в конечном итоге собираетесь хранить билеты на аутентификацию в базе данных или сервере Redis, обратный здесь, что с каждым запросом, содержащим токен-носитель, вы будете проверять это постоянное хранилище в чтобы разрешить Руководство и получить билет снова, чтобы его построить.

Я предлагаю вам использовать JSON Web Токен JWT вместо стандартного формата токенов доступа на предъявителя, для этого вам необходимо реализовать пользовательский маркер доступа формата CustomOAuthProvider в свойстве Provider в OAuthAuthorizationServerOptions как код ниже:

OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      //For Dev enviroment only (on production should be AllowInsecureHttp = false) 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/oauth2/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), 
      Provider = new CustomOAuthProvider(), 
      AccessTokenFormat = new CustomJwtFormat("http://jwtauthzsrv.azurewebsites.net") 
     }; 

Я заметил, что добавление большего количества претензий к токену JWT не будет сильно увеличивать его размер, как в случае формата токена доступа по умолчанию.

Ниже образца из 2 JWT с разными претензиями внутри каждого из них, второй больше, чем первый, всего на 50 символов. Я рекомендую вам проверить кодированный содержание каждого из них с помощью jwt.io Первый JWT:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InRhaXNlZXIiLCJzdWIiOiJ0YWlzZWVyIiwicm9sZSI6WyJNYW5hZ2VyIiwiU3VwZXJ2aXNvciJdLCJpc3MiOiJodHRwOi8vand0YXV0aHpzcnYuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiIwOTkxNTNjMjYyNTE0OWJjOGVjYjNlODVlMDNmMDAyMiIsImV4cCI6MTQxODY0NzMyNywibmJmIjoxNDE4NjQ1NTI3fQ.vH9XPtjtAv2-6SwlyX4fKNJfm5ZTVHd_9a3bRgkA_LI 

Второй JWT (Больше претензий):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InRhaXNlZXIiLCJzdWIiOiJ0YWlzZWVyIiwicm9sZSI6WyJNYW5hZ2VyIiwiU3VwZXJ2aXNvciIsIlN1cGVydmlzb3IxIiwiU3VwZXJ2aXNvcjIiLCJTdXBlcnZpc29yMyJdLCJpc3MiOiJodHRwOi8vand0YXV0aHpzcnYuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiIwOTkxNTNjMjYyNTE0OWJjOGVjYjNlODVlMDNmMDAyMiIsImV4cCI6MTQxODY0NzQ1NiwibmJmIjoxNDE4NjQ1NjU2fQ.TFEGDtz1RN8VmCQu7JH4Iug0B8UlWDLVrIlvc-7IK3E 

Формат JWT становится стандартным способом выпустить OAuth 2.0 токены-носители, а также он будет работать с обновлением токена обновления. Но имейте в виду, что JWT - это только подписанные токены, а не зашифрованные как случай в формате токена доступа по умолчанию, поэтому не храните конфиденциальные данные.

Я написал detailed blog post на bitoftech.net о том, как использовать JWT маркеры в ASP.NET Web API вместе с живым демо API и source code on GIthub, не стесняйтесь проверить его и дайте мне знать, если вам нужна дополнительная помощь.

Удачи вам!

+0

Вы упомянули о работе JWT с refresh_tokens. Можете ли вы уточнить? Прямо сейчас у меня есть реализация, которая даст мне JWT как мой access_token и в том же ответе, он включает гораздо меньший токен (guid), который является моим refresh_token. Это правильный процесс или должен быть refresh_token также JWT с более длительным сроком службы? –

+0

Нет токена обновления - это только идентификатор защищенного билета, хранящийся в вашей базе данных, вы представляете этот идентификатор с помощью grant_type = refresh_token, и если он действителен (не удаляется из БД и не истек), вы получите новый токен доступа JWT, надейтесь, что это будет Чисто. –

+0

Это имеет смысл. Благодарю. –

 Смежные вопросы

  • Нет связанных вопросов^_^