OAuth有助于开发者轻松获取用户信息,这里我将向你展示微软OAuth在react hook中的用法,让我们开始旅程。
在Azure配置
注册你的APP
提示: 记住 application ID 和 Directory ID 我们后面配置需要用到
准备你的react app
Node modules
我们需要以下npm包
shell
npm install @azure/msal-browser
npm install @azure/msal-react
创建一个msconfig.js文件
msconfig.js
js
export const msalConfig = {
auth: {
clientId: "Enter_the_Application_Id_Here", // application id
authority: "https://login.microsoftonline.com/Enter_the_Tenant_Info_Here", // directory id
redirectUri: "http://localhost:3000", // after auth success, will redirect in this uri
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
},
}
创建一个MsAuthProvider
MsAuthProvider
能够帮助我们在react hook下更好的使用微软的OAuth
MsAuthProvider.jsx
jsx
import * from "react";
import { MsalProvider } from '@azure/msal-react';
import { PublicClientApplication } from '@azure/msal-browser';
import { msalConfig } from './msconfig.js';
// create msal instance and export it for using.
export const msalInstance = new PublicClientApplication(msalConfig);
export default function MsAuthProvider({ children }) {
return <MsalProvider instance={msalInstance}>
{children}
</MsalProvider>
}
用 MsAuthProvider 把你的 react App 包裹起来
在App.jsx, 我们需要像下面的代码一样重构一下App。
jsx
import * from 'react';
import { AuthenticatedTemplate, UnauthenticatedTemplate } from '@azure/msal-react';
import App from './App.jsx'
import MsAuthProvider from './msAuthProvider/index.jsx';
import SignIn from './pages/signin/index.jsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
<MsAuthProvider>
<AuthenticatedTemplate>
<App />
</AuthenticatedTemplate>
<UnauthenticatedTemplate>
<SignIn />
</UnauthenticatedTemplate>
</MsAuthProvider>
)
我们可以使用 @azure/msal-react
提供的 AuthenticatedTemplate
和 UnauthenticatedTemplate
,这有助于控制显示组件, 我们不需要控制是否授权的状态, MsAuthProvider
会帮助我们处理这个状态。
创建一个 SignIn component
SignIn component index.jsx
jsx
import * from 'react';
import { Card, Typography, CardBody, CardFooter, Button } from "@material-tailwind/react";
import { useSelector } from "react-redux";
import { useMsal } from "@azure/msal-react";
export default function SignIn() {
const handleLogin = () => {
// this will open a popup for signin, after singin popup will be close, then
// app will redirect to the redirectUri as the config in msalConfig
instance.loginPopup({
scopes: ["User.Read"]
}).catch((e) => console.log(e));
};
return (
<div className="flex justify-center mt-32">
<Card className="w-96">
<CardBody className="flex flex-col gap-4 place-items-center">
<Typography variant="h3">
Sign In
</Typography>
</CardBody>
<CardFooter className="pt-0">
<Button
className="bg-blue-900"
fullWidth
onClick={handleLogin}
>
Sign In With MicroSoft
</Button>
</CardFooter>
</Card>
</div>
)
}
点击登录就会出现以下弹窗
获取用户信息
profile.jsx
jsx
import *, { useEffect } from "react";
import { useMsal } from '@azure/msal-react';
export default function Profile() {
const [profileData, setProfileData] = useState(null);
const { instance, accounts } = useMsal();
const getProfile = async () => {
// get access token by instance, this instance is provided by MsAuthProvider
const accessToken = await instance.acquireTokenSilent({
scopes: ["User.Read"]
account: accounts[0],
}).then((response) => response.accessToken);
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "GET",
headers: headers
};
// fetch user information
fetch("https://graph.microsoft.com/v1.0/me", options)
.then(res => res.json())
.then((res) => setProfileData(res))
}
useEffect(() => {
if (!profileData) {
getProfile();
}
}, [profileData]);
return (
<div className="flex flex-col items-center">
{
profileData && <div className="flex flex-col items-center">
<p>
<strong>First Name: </strong> {profileData.givenName}
</p>
<p>
<strong>Last Name: </strong> {profileData.surname}
</p>
<p>
<strong>Email: </strong> {profileData.userPrincipalName}
</p>
<p>
<strong>Id: </strong> {profileData.id}
</p>
</div>
}
<button onClick={getProfile}>Get user information</button>
</div>
);
};
scopes 参数的 ["User.Read"]
用来获取 access token,['openid']
用来获取 id token。
集成 Axios
Axios 有 interceptors
能帮助我们在请求之前配置一些请求配置。
request.js
js
import axios from 'axios'
import { msalInstance } from './msAuthProvider/index.jsx';
const request = axios.create({
baseURL: '/'
})
// add
request.interceptors.request.use(async config => {
// msalInstance is exported by msAuthProvider file, because we can not use the hook here
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
const accessToken = await instance.acquireTokenSilent({
scopes: ["User.Read"]
account: accounts[0],
}).then((response) => response.accessToken);
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`
}
}
return config;
}, function (error) {
return Promise.reject(error);
});
export default request;
然后我们需要重构一下 profile.jsx
jsx
import *, { useEffect } from "react";
import { useMsal } from '@azure/msal-react';
import request from './request.js'
export default function Profile() {
const [profileData, setProfileData] = useState(null);
const { instance, accounts } = useMsal();
const getProfile = () => {
// replce fetch by axios request
request.get("https://graph.microsoft.com/v1.0/me")
.then((res) => setProfileData(res))
}
useEffect(() => {
if (!profileData) {
getProfile();
}
}, [profileData]);
return (
<div className="flex flex-col items-center">
{
profileData && <div className="flex flex-col items-center">
<p>
<strong>First Name: </strong> {profileData.givenName}
</p>
<p>
<strong>Last Name: </strong> {profileData.surname}
</p>
<p>
<strong>Email: </strong> {profileData.userPrincipalName}
</p>
<p>
<strong>Id: </strong> {profileData.id}
</p>
</div>
}
<button onClick={getProfile}>Get user information</button>
</div>
);
};