我正在尝试在响应中执行Microsoft oauth按钮,该重定向/弹出允许用户登录其Microsoft帐户,然后使用该信息获取访问令牌,然后发送至图形api以获取用户信息进行登录。我正在使用此软件包https://www.npmjs.com/package/msal,并尝试为应用重定向注册一个URL。
问题是React应用正在使用哈希路由器来延迟加载页面,并且为了在Azure AAD中注册重定向URL,它不能是片段。因此,我尝试切换到浏览器路由器,并在本地主机中对其进行测试后,至少从成功的重定向中获得了结果。
然后在生产版本中尝试无法使其成功重定向。每次它重定向,刷新或什至在URL中写入其他路径时,都找不到该页面。我从React-router urls don't work when refreshing or writing manually处了解到此问题。但是现在不确定如何解决此问题。我对编码还很陌生,因此希望获得任何形式的建议。
import React, { Component } from 'react';
import { BrowserRouter,browserHistory,Router, Route, Switch } from 'react-router-dom';
import { ProtectedRoute } from './auth/ProtectedRoute'
const loading = () => <div className="animated fadeIn pt-3 text-center">Loading...</div>;
// Containers
const DefaultLayout = React.lazy(() => import('./containers/DefaultLayout'));
// Pages
const Login = React.lazy(() => import('./views/Pages/Login'));
const Register = React.lazy(() => import('./views/Pages/Register'));
const Page404 = React.lazy(() => import('./views/Pages/Page404'));
const Page500 = React.lazy(() => import('./views/Pages/Page500'));
//const EditInfo = React.lazy(() => import('./views/Pages/EditInfo'));
export class App extends Component {
render() {
return (
<BrowserRouter>
<React.Suspense fallback={loading()}>
<Switch>
<Route exact path="/login" name="Login Page" render={props => <Login {...props}/>} />
<Route exact path="/register" name="Register Page" render={props => <Register {...props}/>} />
<Route exact path="/404" name="Page 404" render={props => <Page404 {...props}/>} />
<Route exact path="/500" name="Page 500" render={props => <Page500 {...props}/>} />
<ProtectedRoute path="/" name="Home" component={DefaultLayout} />
<ProtectedRoute path="/dashboard" name="Home" component={DefaultLayout} />
</Switch>
</React.Suspense>
</BrowserRouter>
);
}
}
我处理配置,重定向,请求的功能。我想重定向到登录页面。但是,在使用浏览器路由器的生产版本中,重定向到服务器上找不到的页面。
import * as Msal from 'msal';
import axios from 'axios'
export function loginOauth () {
var msalConfig = {
auth: {
clientId: 'my client id',
redirectUri: 'http://mysite.io/login'
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: true
}
};
let loginRequest = {
scopes: ["user.read"],
prompt: 'select_account'
}
let accessTokenRequest = {
scopes: ["user.read","profile"]
}
var graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me"
};
var msalInstance = new Msal.UserAgentApplication(msalConfig);
let authRedirectCallBack = (errorDesc, token, error, tokenType) => {
if (token) {
console.log(token);
}
else {
console.log(error + ":" + errorDesc);
}
};
msalInstance.handleRedirectCallback(authRedirectCallBack);
let signIn = () => {
msalInstance.loginRedirect(loginRequest).then(async function (loginResponse) {
return msalInstance.acquireTokenSilent(accessTokenRequest);
}).then(function (accessTokenResponse) {
const token = accessTokenResponse.accessToken;
console.log(token);
}).catch(function (error) {
//handle error
});
}
let acquireTokenRedirectAndCallMSGraph = () => {
//Always start with acquireTokenSilent to obtain a token in the signed in user from cache
msalInstance.acquireTokenSilent(accessTokenRequest).then(function (tokenResponse) {
callMSGraph(graphConfig.graphMeEndpoint, tokenResponse.accessToken, graphAPICallback);
}).catch(function (error) {
console.log(error);
// Upon acquireTokenSilent failure (due to consent or interaction or login required ONLY)
// Call acquireTokenRedirect
if (requiresInteraction(error.errorCode)) {
msalInstance.acquireTokenRedirect(accessTokenRequest);
}
});
}
let callMSGraph = (theUrl, accessToken, callback) => {
console.log(accessToken);
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200)
callback(JSON.parse(this.responseText));
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xmlHttp.send();
}
let graphAPICallback = (data) => {
console.log(data);
}
let requiresInteraction = (errorCode)=> {
if (!errorCode || !errorCode.length) {
return false;
}
return errorCode === "consent_required" ||
errorCode === "interaction_required" ||
errorCode === "login_required";
}
signIn();
}
在重定向和加载页面时,我正在使用componentmount来从会话中获取数据。
export default class Login extends Component{
constructor(props) {
super(props);
this.state = {
modal: false,
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal,
}));
}
handleLogout(){
auth.logout(() => {console.log("logged out")})
this.toggle()
}
componentWillMount() {
var msalConfig = {
auth: {
clientId: 'my_clientid',
redirectUri: 'http://mysite.io/login'
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: true
}
};
var msalInstance = new Msal.UserAgentApplication(msalConfig);
if (msalInstance.getAccount()) {
var tokenRequest = {
scopes: ["user.read"]
};
msalInstance.acquireTokenSilent(tokenRequest)
.then(response => {
callMSGraph(response.accessToken, (data)=>console.log(data))
// get access token from response
// response.accessToken
})
.catch(err => {
// could also check if err instance of InteractionRequiredAuthError if you can import the class.
if (err.name === "InteractionRequiredAuthError") {
return msalInstance.acquireTokenPopup(tokenRequest)
.then(response => {
// get access token from response
// response.accessToken
})
.catch(err => {
// handle error
});
}
});
} else {
// user is not logged in, you will need to log them in to acquire a token
}
let token = sessionStorage.getItem('msal.idtoken');
if(token !== null) {
var decoded = jwt_decode(token);
console.log(decoded);
} else {
console.log("NO token yet");
}
}
render() {
let open;
if(auth.isAuthenticated() === "true"){
open = true
}else{ open = false}
return (<div><button onClick={ () => {loginOauth()}} >Login with Microsoft</button> </div>);
}
答案 0 :(得分:1)
您应该只注册要用户重定向到的基本URL。要允许状态数据(即片段)穿越服务边界,请使用state
参数。
您通过state
参数传递给OAuth的任何信息都将与您的令牌一起返回。然后,您将在返回用户时解析state
。