【发布时间】:2019-06-21 22:40:41
【问题描述】:
我正在尝试实现 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();
}
在重定向和加载页面时,我使用组件将挂载从会话中获取数据。
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>);
}
【问题讨论】:
-
能否请您出示相关代码,以便我们看到您在做什么?
标签: javascript reactjs react-router microsoft-graph-api msal