Как реализовать Microsoft OAUT в приложении реагировать, которое использует хэш-маршрутизатор - PullRequest
1 голос
/ 22 июня 2019

Я пытаюсь реализовать кнопку «oauth» в Microsoft, так как перенаправление / всплывающее окно позволяет пользователю войти в свою учетную запись microsoft, затем использовать информацию, чтобы получить токен доступа, а затем отправить в graph api, чтобы получить информацию о пользователе для входа в систему. Я использую этот пакет https://www.npmjs.com/package/msal и попытался зарегистрировать URL-адрес для перенаправления приложения.

Проблема в том, что приложение реагирования использует хэш-маршрутизатор для отложенной загрузки страниц, и для регистрации URL-адреса перенаправления в Azure AAD он не может быть фрагментом. Поэтому я попытался переключиться на маршрутизатор браузера и после тестирования в локальном хосте по крайней мере получил результаты от успешного перенаправления.

Тогда попытка его в производственной сборке не могла заставить его перенаправить успешно. Каждый раз, когда он перенаправлял, обновлял или даже писал другой путь в URL, он не мог найти страницу. Я прочитал об этой проблеме здесь URL-адреса React-маршрутизатора не работают при обновлении или записи вручную . Но теперь не знаю, как это исправить. Я довольно новичок в программировании, поэтому любая помощь по предложению будет оценена.

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>);
}

1 Ответ

1 голос
/ 24 июня 2019

Вам следует зарегистрировать только базовый URL, на который вы хотите перенаправить пользователя.Чтобы данные вашего состояния (т.е. ваш фрагмент) могли пересекать границы службы, вы используете параметр state.

Любая информация, которую вы передаете в OAuth через параметр state, будет возвращена вместе с вашим токеном.Затем вы анализируете state, когда пользователь возвращается.

...