В Azure У меня есть служба приложений, в которой размещается SPA, и ASP. NET Базовый WebAPI.
Azure Служба приложений
Я активировал Аутентификацию
Аутентификация активна в Сервисе приложений
Когда я пытаюсь получить доступ к SPA, я сначала перенаправляюсь на страницу входа
Логин
После входа в систему устанавливается повар ie (AppServiceAuthSession
).
Повар ie 1
Cook ie 2
WebAPI использует промежуточное ПО app.UseAuthentication();
и [Authorize]
для защиты API.
Перед тем, как SPA вызывает WebAPI, я преобразовываю Cook ie (AppServiceAuthSession
) на токен доступа OAuth с использованием
https://my-app-service.azurewebsites.net/api/values
Это возвращает то, что похоже на access_token.
Token
[{
"access_token": "PAQABAAAAAABeAFzDwllzTYGDLh_qYbH85B5eMV5PaPELRI_hsnIMx2_pQkgf_TZr-9Z_OC26BOyQqoFM2fR...",
"id_token": "...",
"provider_name": "aad",
"refresh_token": "AQABAAAAAABeAFzDwllzTYGDLh_qYbH8k6pCkZIL4QZzJa06T0AYngu8K2WJV...",
"user_claims": [{
"typ": "aud",
"val": "..."
}, {
"typ": "iss",
"val": "https:\/\/sts.windows.net\/...\/"
}, {
"typ": "iat",
"val": "..."
}, {
"typ": "nbf",
"val": "..."
}, {
"typ": "exp",
"val": "..."
}, {
"typ": "aio",
"val": "..."
}, {
"typ": "http:\/\/schemas.microsoft.com\/claims\/authnmethodsreferences",
"val": "pwd"
}, {
"typ": "c_hash",
"val": "..."
}, {
"typ": "ipaddr",
"val": "..."
}, {
"typ": "name",
"val": "..."
}, {
"typ": "nonce",
"val": "..."
}, {
"typ": "http:\/\/schemas.microsoft.com\/identity\/claims\/objectidentifier",
"val": "..."
}, {
"typ": "http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/nameidentifier",
"val": "..."
}, {
"typ": "http:\/\/schemas.microsoft.com\/identity\/claims\/tenantid",
"val": "..."
}, {
"typ": "http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/name",
"val": "..."
}, {
"typ": "http:\/\/schemas.xmlsoap.org\/ws\/2005\/05\/identity\/claims\/upn",
"val": "..."
}, {
"typ": "uti",
"val": "..."
}, {
"typ": "ver",
"val": "1.0"
}
],
"user_id": "...@....onmicrosoft.com"
}
]
Но этот токен, по-видимому, не является JWT.
- При использовании этого токена (в заголовке GET «Авторизация»: «Носитель») для вызова API падает с 401 неавторизованным.
- Использование декодера, такого как jwt.io fail s.
- Токен refre sh не является JWT.
- Идентификатор id_token действителен.
Как получить действительный токен доступа JWT от Повар ie AppServiceAuthSession?
Обновление Возможное решение: не пытайтесь преобразовать повара ie в access_token. Скорее выполните обычный запрос аутентификации OAuth2. Azure распознает, что пользователь уже вошел в систему, и возвращает токен доступа (я использую неявный поток, поэтому токен находится в строке запроса URL).
Чтобы вызвать обычный запрос аутентификации, я делаю
var url = config.authorization_endpoint
+ "?response_type=token id_token"
+ "&client_id=" + client_id
+ "&state=" + state
+ "&scope=" + requested_scopes
+ "&redirect_uri=" + redirect_uri
+ "&nonce=" + nonce;
// Redirect to the authorization server
window.location = url;
Ниже находится SPA
var config = {
client_id: "client_id_hash",
redirect_uri: "https://my-app-service.azurewebsites.net/index.html",
authorization_endpoint: "https://login.microsoftonline.com/tenant-id/oauth2/v2.0/authorize",
token_endpoint: "https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token",
requested_scopes: "openid api://some-guid/user_impersonation"
};
function generateRandomString() {
var array = new Uint32Array(28);
window.crypto.getRandomValues(array);
return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');
}
function parseQueryString(string) {
if (string == "") { return {}; }
var segments = string.split("&").map(s => s.split("="));
var queryString = {};
segments.forEach(s => queryString[s[0]] = s[1]);
return queryString;
}
function parseJwt(token) {
try {
// Get Token Header
const base64HeaderUrl = token.split('.')[0];
const base64Header = base64HeaderUrl.replace('-', '+').replace('_', '/');
const headerData = JSON.parse(window.atob(base64Header));
// Get Token payload and date's
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
const dataJWT = JSON.parse(window.atob(base64));
dataJWT.header = headerData;
return dataJWT;
} catch (err) {
return false;
}
}
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function component() {
const element = document.createElement('div');
const btn = document.createElement('button');
const btnApi = document.createElement('button');
btnApi.innerHTML = 'Call API';
btnApi.onclick = callAPI;
element.appendChild(btnApi);
return element;
}
async function callAPI() {
console.log('callAPI');
const data = await fetchValues();
console.log(data);
const element = document.createElement('div');
element.innerHTML = `API response: ${data.toString()}`;
document.body.appendChild(element);
}
function fetchValues() {
const accessToken = getCookie('access_token');
console.log('Access token (from cookie):', accessToken);
const url = 'https://my-app-service.azurewebsites.net/api/values';
return fetch(url, {
headers: {
"Authorization": "Bearer " + accessToken
}
})
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
return data;
});
}
(async function () {
document.body.appendChild(component());
const url = "https://my-app-service.azurewebsites.net/.auth/me";
const response = await fetch(url);
const data = await response.json();
const accessToken = data[0].access_token
const accessTokenJwt = parseJwt(accessToken);
console.log('accessTokenJwt: ', accessToken, accessTokenJwt);
document.cookie = "access_token=" + accessToken + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;samesite";
}());