należy włączyć generowanie refresh_token poprzez ustawienie w startup.cs:
- wartości ustawienia do AuthorizationEndpointPath = "/ connect/autoryzować"; // potrzebne do refreshtoken
- Ustawianie wartości na TokenEndpointPath = "/ connect/token"; // średnia Token końcowym
W token dostawcy, przed walidacji tokenu żądania na końcu metody HandleTokenrequest, upewnij się, że został ustawiony w trybie offline zakresu:
// 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);
Jeśli to ustawienie poprawnie, powinieneś otrzymać refresh_token, gdy logujesz się z hasłem grant_type.
Następnie od klienta należy wydać następujące żądanie (używam 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'
}
});
}
i to jest to, upewnij się, że dostawca auth w HandleRequestToken nie próbuje manipulować wniosek, który jest typu 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 powinien po prostu być w stanie przejść przez tą metodą i jest obsługiwany przez inny kawałek oprogramowania pośredniczącego, który obsługuje refresh_token.
Jeśli chcesz bardziej dogłębnej wiedzy na temat tego, co serwer uwierzytelniania robi, można rzucić okiem na kodzie OpenIdConnectServerHandler:
https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/blob/master/src/AspNet.Security.OpenIdConnect.Server/OpenIdConnectServerHandler.Exchange.cs
po stronie klienta musi również być w stanie obsłużyć automatyczne odświeżanie tokenu, tutaj jest przykładem przechwytywacza http dla Angular 1.X, gdzie jeden obsługuje 401 reponses, odśwież żeton, a następnie ponowić żądanie:
'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;
}]);
I tu jest przykładem właśnie zrobił dla Aurelia, tym razem zawinięte mojego klienta HTTP do programu obsługi http, który sprawdza, czy token wygasł lub nie. Jeśli wygasł, najpierw odświeży token, a następnie wykona żądanie. Wykorzystuje obietnicę utrzymania spójności interfejsu z usługami danych po stronie klienta. Ten moduł obsługi udostępnia ten sam interfejs, co klient pobierania aurelia.
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);
}
}
}
dla jQuery można wyglądać OAuth jquery:
https://github.com/esbenp/jquery-oauth
nadzieję, że to pomaga.
Powinno zostać (wygasnąć> DateTime.Now) (wygasa> DateTime.UtcNow)? https://docs.asp.net/en/latest/security/authentication/cookie.html sugeruje użycie czasu utc. – Darxtar
Nie, datetime.parse odczytuje wartość ".Token.expires_at" jako UTC i analizuje czas lokalny. ".Token.expires_at" 2016-10-19T16: 02: 39.0008091 + 00: 00 ". – longday
OK, dziękuję za wyjaśnienie =) – Darxtar