app.get("/", async (req, res) => {
const accounts = await tokenCache.getAllAccounts();
if (accounts && accounts.length > 0) {
res.status(200).send(accounts[0]);
}
else {
const authCodeUrlParameters = {
scopes: ['user.read'],
redirectUri: "http://localhost:3000/redirect"
};
cca.getAuthCodeUrl(authCodeUrlParameters)
.then(response => res.redirect(response))
.catch((error) => console.log(JSON.stringify(error)));
}
});
app.get('/redirect', (req, res) => {
const tokenRequest = {
code: req.query.code,
scopes: ['user.read'],
redirectUri: 'http://localhost:3000/redirect'
};
cca.acquireTokenByCode(tokenRequest).then((response) => {
res.redirect('/');
}).catch((error) => {
res.status(500).send(error);
})
})
dotnet new webapp -o 项目名称 -au singleorg --client-id 应用程序编号 --tenant-id 租户编号
可用的身份认证选项如下
修改根目录下面的 program.cs
文件, 这是可选的,默认情况下,如果不加下面的设置,则所有页面都需要身份验证。
builder.services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/Contact");//这个页面需要身份验证
options.Conventions.AuthorizeFolder("/Private");//这个目录需要身份验证
options.Conventions.AllowAnonymousToPage("/Private/PublicPage");//这个页面可匿名访问
options.Conventions.AllowAnonymousToFolder("/Private/PublicPages");//这个目录可匿名访问
});
修改 pages/index.cshtml
的代码如下,直接用 User
对象。在 .cs
文件中,也是用 User
对象。
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">用户信息</h1>
<p>@User.Identity.Name</p>
</div>
dotnet run --urls https://localhost:3000
默认运行 dotnet run
每次的端口可能不一样,所以上面指定了固定的端口,这个需要跟在AAD中注册应用程序时填写的重定向 Url 匹配。请注意,.NET Core要求用https,否则会报一个错误。
/signin-oidc
这个地址是ASP.NET Core
中间件自动监听的。在网站中找不到。
通过下面的命令可以创建项目
dotnet new webapp -o 项目名称 -au singleorg --client-id 应用程序编号 --tenant-id 租户编号 --calls-graph $true --called-api-scopes "mail.read user.read"
配置有关中间件
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
private readonly ILogger<HomeController> _logger;
private readonly GraphServiceClient _graphServiceClient;
private readonly GraphServiceClient _graphServiceClient;
public HomeController(ILogger<HomeController> logger,
IConfiguration configuration,
GraphServiceClient graphServiceClient)
{
_logger = logger;
_graphServiceClient = graphServiceClient;
this._consentHandler = consentHandler;
}
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> Profile()
{
var me = await _graphServiceClient.Me.Request().GetAsync();
ViewData["Me"] = me;
try
{
// Get user photo
using (var photoStream = await _graphServiceClient.Me.Photo.Content.Request().GetAsync())
{
byte[] photoByte = ((MemoryStream)photoStream).ToArray();
ViewData["Photo"] = Convert.ToBase64String(photoByte);
}
}
catch (System.Exception)
{
ViewData["Photo"] = null;
}
return View();
}
无需在代码里面实现身份验证和授权,服务器将发送如下的header信息
x-ms-token-aad-access-token
进行后续调用你可以通过邮件 ares@xizhang.com 与我取得联系,也可以关注 code365xyz
这个微信公众号给我留言。
点击这里 或扫码可以访问配套视频教程。
陈希章 2022年2月 于上海
https://docs.microsoft.com/en-us/samples/azure-samples/active-directory-aspnetcore-webapp-openidconnect-v2/active-directory-aspnetcore-webapp-openidconnect-v2/
如果需要顺便读取Microsoft Graph,则需要按照这里进行配置 https://docs.microsoft.com/zh-cn/azure/app-service/scenario-secure-app-access-microsoft-graph-as-user?tabs=azure-resource-explorer%2Cprogramming-language-nodejs#configure-app-service-to-return-a-usable-access-token
"login": { "loginParameters": [ "response_type=code id_token", "scope=openid offline_access profile https://graph.microsoft.com/Mail.Read" ], "disableWWWAuthenticate": false },