npx create-react-app spa-basic --template typescript
安装
@azure/msal-browser
和@azure/msal-react
两个包
import { render } from "react-dom";
import { PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";
import App from "./App";
const instance = new PublicClientApplication({
auth: {
clientId: "46abe5ec-ccf0-4805-a7b5-f622142b6854",
authority://如果是多租户应用,则为 /common
"https://login.microsoftonline.com/3a6831ab-6304-4c72-8d08-3afe544555dd"
},
cache: {
cacheLocation: "sessionStorage"//还可以设置为localStorage
}
});
const rootElement = document.getElementById("root");
render(
<MsalProvider instance={instance}>
<App />
</MsalProvider>,
rootElement
);
function handleLogin(instance: IPublicClientApplication): void {
instance
.loginPopup()
.then((v) => instance.setActiveAccount(v.account))
.catch((reason) => alert(reason));
}
function handleLogout(instance: IPublicClientApplication): void {
instance.logoutPopup();
}
请注意,还有 loginRedirect
和 logoutRedirect
,但是在某些情况下是不能重定向的
登录成功后可以获得如下的基本信息
export declare type AccountInfo = {
homeAccountId: string;
environment: string;
tenantId: string;
username: string;
localAccountId: string;
name?: string;
idTokenClaims?: object;
};
基于Github进行CI&CD,内置各种模板,以及安全支持,现代静态网站(React+API)
在网站根目录下面创建 staticwebapp.config.json,默认支持 aad
,github
, twitter
三种验证器,也支持自定义 OpenID Connect 提供程序。
{
"routes": [
{
"route": "/*",
"allowedRoles": ["authenticated"]
}
],
"responseOverrides": {
"401": {
"statusCode": 302,
"redirect": "/.auth/login/aad"
}
}
}
在前端代码中直接请求一个特定的地址,就可以获取到当前用户信息。该信息其实是以Cookie保存在浏览器中的。请注意,这里的用户id 并不是用户在AAD中真正的id,而是每个应用都不一样的,有点类似于微信开发中的openid.
async function getUserInfo() {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
}
Azure 静态 Web 应用通过 Azure Functions 提供无服务器 API 终结点,如果网站启用了身份验证,则会自动地在头部中传递加密过的用户信息
module.exports = async function (context, req) {
const header = req.headers['x-ms-client-principal'];
const encoded = Buffer.from(header, 'base64');
const decoded = encoded.toString('ascii');
context.res = {
body: {
clientPrincipal: JSON.parse(decoded),
},
};
};
const getToken = async (
instance: IPublicClientApplication,
scopes: string[]
): Promise<string> => {
const request = { scopes: scopes };
try {
const result = await instance.acquireTokenSilent(request);
return result.accessToken;
} catch (error) {
try {
const result = await instance.acquireTokenPopup(request);
return result.accessToken;
} catch (error) {
throw error;
}
}
};
安装 @microsoft/microsoft-graph-client
和 @microsoft/microsoft-graph-types
import { Client } from "@microsoft/microsoft-graph-client";
import { Message, User } from "@microsoft/microsoft-graph-types";
async function getUserProfile(token: string) {
const client = Client.init({
authProvider: (done) => done(undefined, token)
});
return client.api("/me").get();
}
@microsoft/mgt-element
@microsoft/mgt-msal2-provider
@microsoft/mgt-react
@microsoft/microsoft-graph-types
import { Providers } from "@microsoft/mgt-element";
import { Msal2Provider } from "@microsoft/mgt-msal2-provider";
Providers.globalProvider = new Msal2Provider({
clientId: "397b5acf-6a97-4307-a87e-b8e691e54d41",
authority:
"https://login.microsoftonline.com/3a6831ab-6304-4c72-8d08-3afe544555dd",
loginType: 0,
scopes: ["User.Read", "Mail.Read"]
});
import {Login,Agenda,FileList,People,Providers,ProviderState,} from "@microsoft/mgt-react";
function useIsSignIn(): [boolean] {
const [isSignIn, setIsSignIn] = useState(false);
useEffect(() => {
const updateState = () => {
const provider = Providers.globalProvider;
setIsSignIn(provider && provider.state === ProviderState.SignedIn);
};
Providers.onProviderUpdated(updateState);
updateState();
return () => Providers.removeProviderUpdatedListener(updateState);
}, []);
return [isSignIn];
}
// 定义一个模板来显示邮件
const EmailItem = (props: MgtTemplateProps) => {
const message: Message = props.dataContext;
return <div>{message.subject}</div>;
};
// 在界面合适地方使用Get组件
<Get scopes={["Mail.Read"]} resource="/me/messages">
<EmailItem template="value" />
</Get>
你可以通过邮件 ares@xizhang.com 与我取得联系,也可以关注 code365xyz
这个微信公众号给我留言。
点击这里 或扫码可以访问配套视频教程。
陈希章 2022年2月 于上海
默认的那个登录页面是英文的,而且无法定制,如果要支持自定义验证,也很简单,请参考 https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-custom?tabs=aad 1. 注册一个应用程序,添加一个密钥 1. 选择Web应用程序,redirect地址是:https://icy-pebble-04e0d6900.1.azurestaticapps.net/.auth/login/aad/callback 1. 勾选上 隐式授权中的 id_token 这个选项 配置文件中添加 "auth": { "identityProviders": { "azureActiveDirectory": { "registration": { "openIdIssuer": "https://login.microsoftonline.com/3a6831ab-6304-4c72-8d08-3afe544555dd/v2.0", "clientIdSettingName": "AZURE_CLIENT_ID", "clientSecretSettingName": "AZURE_CLIENT_SECRET" } } } }, 在静态网站启用标准价格层(这样才能支持自定义),然后添加配置项 AZURE_CLIENT_ID 和 AZURE_CLIENT_SECRET