2016-10-13 2 views
8

Я настроил ASOS OpenIdConnect Server и приложение asp.net core mvc, использующее «Microsoft.AspNetCore.Authentication.OpenIdConnect»: 1.0.0 и «Microsoft.AspNetCore.Authentication.Cookies»: «1.0.0». Я протестировал рабочий процесс «Авторизация» и все работает.Как обработать истекший токен доступа в ядре asp.net с помощью токена обновления с помощью OpenId Connect

Клиентское веб-приложение обрабатывает аутентификацию, как ожидается, и создает файл cookie хранение id_token, access_token и refresh_token.

Как заставить Microsoft.AspNetCore.Authentication.OpenIdConnect запросить новый access_token, когда он истекает?

Приложение mpc core asp.net игнорирует истекший access_token.

Я бы хотел, чтобы openidconnect смотрел просроченный access_token, затем позвоните с помощью токена обновления, чтобы получить новый access_token. Он также должен обновлять значения cookie. Если запрос обновления токена не работает, я бы ожидал, что openidconnect «выйдет» из файла cookie (удалите его или что-то еще).

app.UseCookieAuthentication(new CookieAuthenticationOptions 
     { 
      AutomaticAuthenticate = true, 
      AutomaticChallenge = true, 
      AuthenticationScheme = "Cookies" 
     }); 

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions 
     { 
      ClientId = "myClient", 
      ClientSecret = "secret_secret_secret", 
      PostLogoutRedirectUri = "http://localhost:27933/", 
      RequireHttpsMetadata = false, 
      GetClaimsFromUserInfoEndpoint = true, 
      SaveTokens = true, 
      ResponseType = OpenIdConnectResponseType.Code, 
      AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet, 
      Authority = http://localhost:27933, 
      MetadataAddress = "http://localhost:27933/connect/config", 
      Scope = { "email", "roles", "offline_access" }, 
     }); 

ответ

9

Кажется, нет программирования в аутентификации openidconnect для ядра asp.net для управления access_token на сервере после получения.

Я обнаружил, что могу перехватить событие проверки файлов cookie и проверить, истек ли токен доступа. Если да, сделайте ручной HTTP-вызов конечной точке маркера с помощью grant_type = refresh_token.

Вызывая context.ShouldRenew = true; это заставит cookie обновляться и отправляться обратно клиенту в ответ.

Я представил основы того, что я сделал, и будет работать, чтобы обновить этот ответ, как только работа будет решена.

app.UseCookieAuthentication(new CookieAuthenticationOptions 
     { 
      AutomaticAuthenticate = true, 
      AutomaticChallenge = true, 
      AuthenticationScheme = "Cookies", 
      ExpireTimeSpan = new TimeSpan(0, 0, 20), 
      SlidingExpiration = false, 
      CookieName = "WebAuth", 
      Events = new CookieAuthenticationEvents() 
      { 
       OnValidatePrincipal = context => 
       { 
        if (context.Properties.Items.ContainsKey(".Token.expires_at")) 
        { 
         var expire = DateTime.Parse(context.Properties.Items[".Token.expires_at"]); 
         if (expire > DateTime.Now) //TODO:change to check expires in next 5 mintues. 
         { 
          logger.Warn($"Access token has expired, user: {context.HttpContext.User.Identity.Name}"); 

          //TODO: send refresh token to ASOS. Update tokens in context.Properties.Items 
          //context.Properties.Items["Token.access_token"] = newToken; 
          context.ShouldRenew = true; 
         } 
        } 
        return Task.FromResult(0); 
       } 
      } 
     }); 
+0

Должно ли (expire> DateTime.Now) фактически стать (expire> DateTime.UtcNow)? https://docs.asp.net/ru/latest/security/authentication/cookie.html предлагает использовать время utc. – Darxtar

+0

Нет, datetime.parse считывает значение «.Token.expires_at» в формате UTC и анализирует локальное время. «.Token.expires_at» 2016-10-19T16: 02: 39.0008091 + 00: 00 ». – longday

+0

Хорошо, спасибо за разъяснение =) – Darxtar

1

Вы должны включить генерацию refresh_token, установив в startup.cs:

  • значения настройки для AuthorizationEndpointPath = "/ подключения/авторизовать"; // требуется для refreshtoken
  • Установка значений в TokenEndpointPath = "/ connect/token"; // Маркер имя конечной точки

В вашем лексем поставщика до проверки маркера запроса в конце метода HandleTokenrequest, убедитесь, что вы установили автономную сферу:

 // Call SetScopes with the list of scopes you want to grant 
     // (specify offline_access to issue a refresh token). 
     ticket.SetScopes(
      OpenIdConnectConstants.Scopes.Profile, 
      OpenIdConnectConstants.Scopes.OfflineAccess); 

Если это установка правильно, вы должны получить refresh_token назад при входе с паролем grant_type.

Тогда из вашего клиента вы должны выдать следующий запрос (я использую Aurelia):

refreshToken() { 
    let baseUrl = yourbaseUrl; 

    let data = "client_id=" + this.appState.clientId 
       + "&grant_type=refresh_token" 
       + "&refresh_token=myRefreshToken"; 

    return this.http.fetch(baseUrl + 'connect/token', { 
     method: 'post', 
     body : data, 
     headers: { 
      'Content-Type': 'application/x-www-form-urlencoded', 
      'Accept': 'application/json' 
     } 
    }); 
} 

и это его, убедитесь, что ваш провайдер аутентификации в HandleRequestToken не пытается манипулировать запрос, который типа refresh_token:

public override async Task HandleTokenRequest(HandleTokenRequestContext context) 
    { 
     if (context.Request.IsPasswordGrantType()) 
     { 
      // Password type request processing only 
      // code that shall not touch any refresh_token request 
     } 
     else if(!context.Request.IsRefreshTokenGrantType()) 
     { 
      context.Reject(
        error: OpenIdConnectConstants.Errors.InvalidGrant, 
        description: "Invalid grant type."); 
      return; 
     } 

     return; 
    } 

refresh_token должен просто быть в состоянии пройти через этот метод и обрабатывается другой частью промежуточного слоя, который обрабатывает refresh_token.

Если вы хотите более глубокие знания о том, что делает сервер аутентификации, вы можете взглянуть на код в OpenIdConnectServerHandler:

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/blob/master/src/AspNet.Security.OpenIdConnect.Server/OpenIdConnectServerHandler.Exchange.cs

На стороне клиента вы должны быть в состоянии обработать автоматическое обновление токена, вот пример перехватчика http для Angular 1.X, где один обрабатывает 401 Reponses, обновить маркер, а затем повторите запрос:

'use strict'; 
app.factory('authInterceptorService', 
    ['$q', '$injector', '$location', 'localStorageService', 
    function ($q, $injector, $location, localStorageService) { 

    var authInterceptorServiceFactory = {}; 
    var $http; 

    var _request = function (config) { 

     config.headers = config.headers || {}; 

     var authData = localStorageService.get('authorizationData'); 
     if (authData) { 
      config.headers.Authorization = 'Bearer ' + authData.token; 
     } 

     return config; 
    }; 

    var _responseError = function (rejection) { 
     var deferred = $q.defer(); 
     if (rejection.status === 401) { 
      var authService = $injector.get('authService'); 
      console.log("calling authService.refreshToken()"); 
      authService.refreshToken().then(function (response) { 
       console.log("token refreshed, retrying to connect"); 
       _retryHttpRequest(rejection.config, deferred); 
      }, function() { 
       console.log("that didn't work, logging out."); 
       authService.logOut(); 

       $location.path('/login'); 
       deferred.reject(rejection); 
      }); 
     } else { 
      deferred.reject(rejection); 
     } 
     return deferred.promise; 
    }; 

    var _retryHttpRequest = function (config, deferred) { 
     console.log('autorefresh'); 
     $http = $http || $injector.get('$http'); 
     $http(config).then(function (response) { 
      deferred.resolve(response); 
     }, 
     function (response) { 
      deferred.reject(response); 
     }); 
    } 

    authInterceptorServiceFactory.request = _request; 
    authInterceptorServiceFactory.responseError = _responseError; 
    authInterceptorServiceFactory.retryHttpRequest = _retryHttpRequest; 

    return authInterceptorServiceFactory; 
}]); 

А вот пример я просто сделал для Aurelia, на этот раз я обернутый мой клиент HTTP в обработчик HTTP, который проверяет, если токен истек или нет. Если он истек, он сначала обновит токен, а затем выполнит запрос. Он использует обещание поддерживать совместимость интерфейса с клиентскими службами данных. Этот обработчик предоставляет тот же интерфейс, что и клиент aurelia-fetch.

import {inject} from 'aurelia-framework'; 
import {HttpClient} from 'aurelia-fetch-client'; 
import {AuthService} from './authService'; 

@inject(HttpClient, AuthService) 
export class HttpHandler { 

    constructor(httpClient, authService) { 
     this.http = httpClient; 
     this.authService = authService; 
    } 

    fetch(url, options){ 
     let _this = this; 
     if(this.authService.tokenExpired()){ 
      console.log("token expired"); 
      return new Promise(
       function(resolve, reject) { 
        console.log("refreshing"); 
        _this.authService.refreshToken() 
        .then(
         function (response) { 
          console.log("token refreshed"); 
         _this.http.fetch(url, options).then(
          function (success) { 
           console.log("call success", url); 
           resolve(success); 
          }, 
          function (error) { 
           console.log("call failed", url); 
           reject(error); 
          }); 
         }, function (error) { 
          console.log("token refresh failed"); 
          reject(error); 
        }); 
       } 
      ); 
     } 
     else { 
      // token is not expired, we return the promise from the fetch client 
      return this.http.fetch(url, options); 
     } 
    } 
} 

Для JQuery вы можете смотреть Jquery OAuth:

https://github.com/esbenp/jquery-oauth

Надеется, что это помогает.

+0

Как получить клиентскую сторону для автоматической обработки истекшего доступа access_token путем запроса нового токена с помощью refresh_token? Я использую клиентскую библиотеку «Microsoft.AspNetCore.Authentication.OpenIdConnect»: «1.0.0 .Если мне нужно обработать токен обновления вручную, какие лучшие методы? Как обновить клиентский файл cookie? – longday

+0

Реализация зависит от вашего frontend framework ... Я использую токены OAuth 2, поэтому я фактически устанавливаю токен в куки-файл, прежде чем отправить его клиенту ... Если у печенья есть то же имя, он будет заменен новым. У вас есть 2 способы автоматического обновления: 1) Профилактический, где вы проверяете время истечения срока действия токена и обновляете до выполнения фактически запроса. 2) Reactive: вы слушаете статусы http в своем клиенте, и если вы получаете 401, вы обновляете токен затем повторите запрос.Если вы используете Angular или Aurelia, вы можете настроить HTTP-перехватчик – Darxtar

+0

Я добавил пример моего ответа для углового 1.X, надеюсь, что это поможет. – Darxtar

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