
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