通过Microsoft Identity Platform获取访问令牌,包括用户认证和无用户认证方式。
前言
一开始是通过调用微软的https://login.microsoftonline.com,让用户自己输入微软账号密码完成登录认证,认证之后重定向回网页继续操作,后面客户说不一定所有人都记得自己的微软账号密码,要求改成自动登录,之后就改成了完全无用户的认证,确实实现了group内所有成员的信息获取,但是客户考虑这样权限太大,可访问的信息太多,所以最后还是改成了通过用户认证,只不过认证用户是group管理员,然后操作group内其他成员的outlook事件。
所以总结下来这次实现了以下三次认证方式:
- 通过Microsoft 标识平台 ,用户完成账号登录后,获取访问令牌并重定向返回。
- 使用Client Secret value,完成无用户的身份认证。
- 使用代表用户账号,无需用户手动登录,自动完成身份认证。
一,通过Microsoft 标识平台 ,用户完成账号登录后,获取访问令牌并重定向返回。
这里以官方的angularDemo来介绍需要用户手动入力账号密码完成认证的情况举例,从github下载代码,简单配置后(npm install)运行结果如下
上图就是通过用户手动输入微软账号密码来实现身份认证,认证完成之后如下图
认证成功如上图所示
这里比较关键的认证处理代码如下
一个是通过引入 import { MsalService } from '@azure/msal-angular',来调用loginPopup方法,传入OAuthSettings实现认证
async signIn(): Promise<void> {
let result = await this.msalService.loginPopup(OAuthSettings)
.catch((reason) => {
this.alertsService.addError('Login failed', JSON.stringify(reason, null, 2));
});
if (result) {
this.authenticated = true;
this.user = await this.getUser();
}
}
// access Token 获取
async getAccessToken(): Promise<string> {
let result = await this.msalService.acquireTokenSilent(OAuthSettings)
.catch((reason) => {
this.alertsService.addError('Get token failed', JSON.stringify(reason, null, 2));
});
if (result) {
return result.accessToken;
}
// Couldn't get a token
this.authenticated = false;
return null;
}
这里是获取accessToken注册import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';服务,进而调用Microsoft Graph API获取信息。
this.graphClient = Client.init({
authProvider: async (done) => {
// Get the token from the auth service
let token = await this.authService.getAccessToken()
.catch((reason) => {
done(reason, null);
});
if (token)
{
done(null, token);
} else {
done("Could not get an access token", null);
}
}
});
官方的NodeJs Demo使用之前要修改example.env配置信息并npm install,关键代码如下,
二,使用Client Secret value,完成无用户的身份认证。
无用户认证非常关键地方是使用到CLIENT_SECRET ,就是之前的文章提到的secret value。
还有之前Microsoft Azure注册的API permission必须追加 application permissions相关权限。
第一步获取accessToken,这里使用axios模块发起http请求,nodeJS关键代码
import axios from 'axios';
const querystring: any = require('querystring');
const TENANT_ID = 'xxxx'
const CLIENT_ID = 'xxxx';
const CLIENT_SECRET = 'xxxx';
(async () => {
const qs = querystring.stringify({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: 'https://graph.microsoft.com/.default',
grant_type: 'client_credentials'
});
const url = `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`;
const result = await axios.request({
url,
method: "POST",
data: qs
});
const access_token = result.data.access_token;
console.log(access_token);
})();
不使用@microsoft/microsoft-graph-client的情况下,通过access token 调用Microsoft Graph API
import axios from 'axios';
const ACCESS_TOKEN = 'xxxx';
(async () => {
const itemList = [];
const url = 'https://graph.microsoft.com/v1.0/groups';
let page = url;
do {
const result = await axios.request({
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`
},
url: page,
method: "GET"
});
itemList.push(...result.data.value);
page = result.data["@odata.nextLink"];
} while (page);
console.log(itemList);
})();
使用@microsoft/microsoft-graph-client的情况下,通过access token 调用Microsoft Graph API
var graph = require('@microsoft/microsoft-graph-client');
// graph.Client注册
function getAuthenticatedClient(accessToken) {
// Initialize Graph client
const client = graph.Client.init({
// Use the provided access token to authenticate
// requests
authProvider: (done) => {
done(null, accessToken);
}
});
return client;
}
module.exports = {
getUserDetails: async function(accessToken,userPrincipalName) {
const client = getAuthenticatedClient(accessToken);
//const user = await client.api('/me')
const user = await client.api(`/users/${userPrincipalName}`)
.select('displayName,givenName,jobTitle,mail,mobilePhone,officeLocation,preferredLanguage,surname,userPrincipalName,id,mailboxSettings')
.get();
return user;
},
};
3.使用代表用户账号,自动完成身份认证。
相较于之前的无用户认证,只要修改的代码如下
import axios from 'axios';
const querystring: any = require('querystring');
const TENANT_ID = 'xxxx'
const CLIENT_ID = 'xxxx';
//const CLIENT_SECRET = 'xxxx';
const USER_ID = 'xxxx';
const USER_PASSWORD = 'xxxx';
(async () => {
const qs = querystring.stringify({
client_id: CLIENT_ID,
username:USER_ID ,
password:USER_PASSWORD,
grant_type: 'password'
});
const url = `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`;
const result = await axios.request({
url,
method: "POST",
data: qs
});
const access_token = result.data.access_token;
console.log(access_token);
})();
以上就是三种认证方式,关于获取的access Token 可以通过JWT解析来查看返回的信息,比如通过无用户认证获取的access Token解析如下,使用用户获取的access Token会稍微有点不同,如下第二张图
无用户认证的access Token
有用户认证的access Token