Arc*_*igo 8 azure-ad-msal blazor .net-5 blazor-webassembly
这个问题没有真正的解决方案,只有各种解决方法,直到 net7 出现。在 net7 中,我们应该再次能够根据https://github.com/dotnet/aspnetcore/pull/43954在一次调用中从多个源请求范围
我有一个 .net5 blazor web assembly 应用程序,使用 msal auth for azure 设置。
services.AddMsalAuthentication(options =>
{
configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("api://xxxxx/API.Access"); // API
options.ProviderOptions.Cache.CacheLocation = "localStorage";
});
Run Code Online (Sandbox Code Playgroud)
这很好用。
此外,我需要访问 Microsoft graph。我已经使用 graph sdk 完成了此操作,并为 graph sdk 提供了身份验证处理程序
public class GraphAuthenticationProvider : IAuthenticationProvider
{
private readonly NavigationManager _navigationManager;
public GraphAuthenticationProvider(IAccessTokenProvider tokenProvider, NavigationManager navigationManager)
{
TokenProvider = tokenProvider;
_navigationManager = navigationManager;
}
public IAccessTokenProvider TokenProvider { get; }
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
string[] scopes = new[] { "https://graph.microsoft.com/Mail.ReadWrite", "https://graph.microsoft.com/Mail.Send" };
var result = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions()
{
Scopes = scopes,
ReturnUrl = _navigationManager.Uri
});
if (result.TryGetToken(out var token))
{
request.Headers.Authorization ??= new AuthenticationHeaderValue(
"Bearer", token.Value);
}
else
{
_navigationManager.NavigateTo(result.RedirectUrl);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎是根据我能找到的文档执行此操作的方法,尽管它似乎假设您正在尝试在同一资源上获取其他范围。 https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassemble/additional-scenarios?view=aspnetcore-5.0#request-additional-access-tokens
这有两个问题:
我无法找到具有多个资源的 blazor web assembly msal 的任何文档。有人可以解释我做错了什么或指出我正确的文档吗?
public class GraphAuthorizationMessageHandler : AuthorizationMessageHandler
{
public GraphAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(authorizedUrls: new[] { "https://graph.microsoft.com/" }, scopes: new[] { "https://graph.microsoft.com/Mail.ReadWrite", "https://graph.microsoft.com/Mail.Send" });
}
}
Run Code Online (Sandbox Code Playgroud)
services.AddScoped<CustomAuthorizationMessageHandler>();
services.AddScoped<GraphAuthenticationProvider>();
services.AddScoped<GraphHttpProvider>();
services.AddScoped<GraphAuthorizationMessageHandler>();
services.AddHttpClient<GraphHttpProvider>(
client => client.BaseAddress = new Uri("https://graph.microsoft.com"))
.AddHttpMessageHandler<GraphAuthorizationMessageHandler>();
services.AddScoped(sp =>
new GraphServiceClient(
sp.GetRequiredService<GraphAuthenticationProvider>(),
sp.GetRequiredService<GraphHttpProvider>())
);
Run Code Online (Sandbox Code Playgroud)
编辑:相关的 github 问题https://github.com/dotnet/aspnetcore/issues/33241 - 似乎目前此功能存在缺陷。
解决方法 - 不幸的是,这不是上述问题的解决方案
发布在这里以防对其他人有用。首先,将以下内容注入到您要使用的组件中:
@inject IAccessTokenProvider TokenProvider
Run Code Online (Sandbox Code Playgroud)
登录后,一旦获得服务器授权,您就可以进行以下调用(一旦用户通过标准登录过程对服务器进行身份验证,此操作就会在后台以静默方式完成):
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { "openid", "offline_access", "https://graph.microsoft.com/.default" }
});
if (tokenResult != null && tokenResult.TryGetToken(out var token))
{
user.GraphToken = token.Value;
var response = await Http.PostAsJsonAsync("UserController/graph", user);
user = await response.Content.ReadFromJsonAsync<UserObj>();
}
Run Code Online (Sandbox Code Playgroud)
在上面的范围数组中,您可以定义您希望为其获取令牌的资源。然后只需在服务器端进行图形调用即可:
public async Task<UserObj> GetMe(string accessToken)
{
UserObj response = new UserObj();
string url = "https://graph.microsoft.com/v1.0/me/?$select=displayName,givenName,department,jobTitle,officeLocation,surname,preferredName,mail";
HttpWebRequest requestObj = (HttpWebRequest)WebRequest.Create(url);
requestObj.Method = "Get";
requestObj.ContentType = "application/json";
requestObj.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse responseObj = null;
responseObj = (HttpWebResponse)await requestObj.GetResponseAsync();
if (responseObj.StatusCode != HttpStatusCode.OK)
{
using (var stream = responseObj.GetResponseStream())
using (var reader = new StreamReader(stream))
{
response.Error = String.Format("There was an issue: {0}", reader.ReadToEnd());
}
}
else
{
using (var stream = responseObj.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string json = reader.ReadToEnd();
response = JsonConvert.DeserializeObject<UserObj>(json);
}
}
return response;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1761 次 |
| 最近记录: |