I am working on a single page application (SPA) app that grants access to specific paths in the application, based on roles setup in Azure AD for the user logging in. As per this https://github.com/Azure-Samples/ms-identity-javascript-react-tutorial/tree/main/5-AccessControl/1-call-api-roles
This is my 'authConfig.js' file - you can see the redirectUri
const clientId = window.REACT_APP_CLIENTID
export const msalConfig = {
auth: {
clientId: clientId,
authority: window.REACT_APP_AUTHORITY,
redirectUri: 'http://localhost:3000/todolist/', // You must register this URI on Azure Portal/App Registration. Defaults to window.location.origin
postLogoutRedirectUri: "/", // Indicates the page to navigate after logout.
navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response.
},
cache: {
cacheLocation: "sessionStorage", // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
}
}
}
}
};
/**
* Add here the endpoints and scopes when obtaining an access token for protected web APIs. For more information, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
*/
export const protectedResources = {
apiTodoList: {
todoListEndpoint: window.REACT_APP_APIENDPOINT+"/api/v2/support/list",
scopes: [window.REACT_APP_APIENDPOINT+"/access_as_user"],
},
}
/**
* Scopes you add here will be prompted for user consent during sign-in.
* By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
* For more information about OIDC scopes, visit:
* https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
export const loginRequest = {
scopes: [...protectedResources.apiTodoList.scopes]
};
export const appRoles = {
TaskUser: "TaskUser",
TaskAdmin: "TaskAdmin",
TrialAdmin: "Trial.Admin",
GlobalAdmin: "Global.Admin"
}
Here is the App.jsx file (I believe there needs to be some change made here). You can see 'RouteGuard' that renders the Component {TodoList}, when the path 'todolist' is accessed.
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { MsalProvider } from "@azure/msal-react";
import { RouteGuard } from './components/RouteGuard';
import { PageLayout } from "./components/PageLayout";
import { TodoList } from "./pages/TodoList";
import { appRoles } from "./authConfig";
import "./styles/App.css";
const Pages = () => {
return (
<Switch>
<RouteGuard
exact
path='/todolist/'
roles={[appRoles.TaskUser, appRoles.TaskAdmin, appRoles.TrialAdmin, appRoles.GlobalAdmin]}
Component={TodoList}
/>
</Switch>
)
}
/**
* msal-react is built on the React context API and all parts of your app that require authentication must be
* wrapped in the MsalProvider component. You will first need to initialize an instance of PublicClientApplication
* then pass this to MsalProvider as a prop. All components underneath MsalProvider will have access to the
* PublicClientApplication instance via context as well as all hooks and components provided by msal-react. For more, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-react/docs/getting-started.md
*/
const App = ({ instance }) => {
return (
<Router>
<MsalProvider instance={instance}>
<PageLayout>
<Pages instance={instance} />
</PageLayout>
</MsalProvider>
</Router>
);
}
export default App;
So as far as my understanding goes, the path 'todolist' is accessed with the listed role, and component is rendered
When logged in, The navigation bar at the top renders with login request, after authentication (). It has the button rendered, with a click function that 'href's to the path '/todolist'.
import { AuthenticatedTemplate, UnauthenticatedTemplate, useMsal } from "@azure/msal-react";
import { Nav, Navbar, Button, Dropdown, DropdownButton} from "react-bootstrap";
import React, { useState, useEffect } from "react";
import { loginRequest } from "../authConfig";
import { InteractionStatus, InteractionType } from "@azure/msal-browser";
import "../styles/App.css";
import logo from "../public/images/logo.jpg";
export const NavigationBar = (props) => {
const { instance } = useMsal();
const { inProgress } = useMsal();
const [isAuthorized, setIsAuthorized] = useState(false);
//The below function is needed incase you want to login using Popup and not redirect
const handleLogin = () => {
instance.loginPopup(loginRequest)
.catch((error) => console.log(error))
}
/**
* Most applications will need to conditionally render certain components based on whether a user is signed in or not.
* msal-react provides 2 easy ways to do this. AuthenticatedTemplate and UnauthenticatedTemplate components will
* only render their children if a user is authenticated or unauthenticated, respectively.
*/
return (
<>
<Navbar className="color-custom" variant="dark">
<a className="navbar-brand" href="/"><img src={logo} className="navbarLogo" alt="TODDOLIST1"/></a>
<AuthenticatedTemplate>
<Nav.Link as={Button} id="signupbutton" variant="dark" className="signupNav" href="/todolist"><strong>List</strong></Nav.Link>
<Button variant="warning" className="ml-auto" drop="left" title="Sign Out" onClick={() => instance.logoutRedirect({ postLogoutRedirectUri: "/" })}><strong>Sign Out</strong></Button>
</AuthenticatedTemplate>
<UnauthenticatedTemplate>
<Button variant="dark" className="ml-auto" drop="left" title="Sign In" onClick={() => instance.loginRedirect(loginRequest)}>Sign In</Button>
</UnauthenticatedTemplate>
</Navbar>
</>
);
};
Here is the RouteGuard.jsx component that renders based on roles/authorization.
import React, { useState, useEffect } from "react";
import { Route } from "react-router-dom";
import { useMsal } from "@azure/msal-react";
export const RouteGuard = ({ Component, ...props }) => {
const { instance } = useMsal();
const [isAuthorized, setIsAuthorized] = useState(false);
const onLoad = async () => {
const currentAccount = instance.getActiveAccount();
if (currentAccount && currentAccount.idTokenClaims['roles']) {
let intersection = props.roles
.filter(role => currentAccount.idTokenClaims['roles'].includes(role));
if (intersection.length > 0) {
setIsAuthorized(true);
}
}
}
useEffect(() => {
onLoad();
}, [instance]);
return (
<>
{
isAuthorized
?
<Route {...props} render={routeProps => <Component {...routeProps} />} />
:
<div className="data-area-div">
<h3>You are unauthorized to view this content.</h3>
</div>
}
</>
);
};
I want the application to directly go to the '/todolist' and render the components within. My redirect uri, does not seem to work. When i login with the required role, it always renders 'You are unauthorized to view this content' as per the RouteGuard file. The URI is /signuplist/ but still the children props are not rendered. ONLY WHEN I CLICK the button 'Todolist' (as per NavigationBar.jsx), does it go and render the child props properly. Redirection does not work as expected. I want it to directly go to /todolist and render the page, child components Any suggestions ?
3条答案
按热度按时间hyrbngr71#
您可以尝试从onload方法签名中删除async吗?
wgx48brx2#
你是否在Azure门户上将“http://localhost:3000/todolist/”注册为有效的重定向URI。你可以根据角色拥有多个重定向URI,但所有URI都必须在Azure门户上你的应用下注册。
https://learn.microsoft.com/en-ca/azure/active-directory/develop/quickstart-register-app#register-an-application
重定向URI是Microsoft身份平台重定向用户客户端并在身份验证后发送安全令牌的位置。
2vuwiymt3#
如果我最后的评论对你有用,让我把它变成一个正式的回答,这样就可以记录下来。
基本上,
定义:const {示例,帐户,进行中} = useMsal();
然后尝试在inProgress!== 'login'时重定向。