ReactJs和MSAL.js未经授权的401

时间:2018-08-20 11:12:12

标签: javascript reactjs azure azure-functions msal

我有一个非常基本的React App,用户可以登录并点击一些MS Graph端点,一旦用户同意,这将毫无问题。我还有另一个请求触发一个匿名的Azure函数,该函数返回一些JSON,没问题。

我遇到的问题与试图向使用MSAL.js lib的AD锁定的Azure Function Api发出请求有关。

我正在使用https://github.com/sunilbandla/react-msal-sample

App.js

import React, { Component } from 'react';
import './App.css';
import AuthService from './services/auth.service';
import GraphService from './services/graph.service';
import HelloService from './services/hello.service';

class App extends Component {
  constructor() {
    super();
    this.authService = new AuthService();
    this.graphService = new GraphService();
    this.helloService = new HelloService();
    this.state = {
      user: null,
      userInfo: null,
      apiCallFailed: false,
      loginFailed: false
    };
  }
  componentWillMount() {}

  callAPI = () => {
    this.setState({
      apiCallFailed: false
    });
    this.authService.getToken().then(
      token => {
        this.graphService.getUserInfo(token).then(
          data => {
            this.setState({
              userInfo: data
            });
          },
          error => {
            console.error(error);
            this.setState({
              apiCallFailed: true
            });
          }
        );
      },
      error => {
        console.error(error);
        this.setState({
          apiCallFailed: true
        });
      }
    );
  };

  callHelloAPI = () => {
    this.setState({
      apiCallFailed: false
    });
    this.authService.getToken().then(
      token => {
        this.helloService.callApi(token).then(
          data => {
            this.setState({
              userInfo: data
            });
            console.log(data);
          },
          error => {
            console.error(error);
            this.setState({
              apiCallFailed: true
            });
          }
        );
      },
      error => {
        console.error(error);
        this.setState({
          apiCallFailed: true
        });
      }
    );
  };

  getTheToken = () => {
    console.log('Get Token:');
    this.authService.getToken().then(token => {
      console.log(token);
    });
  }

  logout = () => {
    this.authService.logout();
  };

  login = () => {
    this.setState({
      loginFailed: false
    });
    this.authService.login().then(
      user => {
        if (user) {
          console.log(user);
          this.setState({
            user: user
          });
        } else {
          this.setState({
            loginFailed: true
          });
        }
      },
      () => {
        this.setState({
          loginFailed: true
        });
      }
    );
  };

  render() {
    let templates = [];
    if (this.state.user) {
      templates.push(
        <div key="loggedIn">
          <button onClick={this.callAPI} type="button">
            Call MS Graph
          </button>
          <button onClick={this.callHelloAPI} type="button">
            Call Azure Function
          </button>
          <button onClick={this.getTheToken}>
          Get The Token (JWT / Cookie)
          </button>
          <button onClick={this.logout} type="button">
            Logout
          </button>
          <h3>Hello {this.state.user.name}</h3>
          <h4>{this.state.user.displayableId}</h4>
        </div>
      );
    } else {
      templates.push(
        <div key="loggedIn">
          <button onClick={this.login} type="button">
            Login with Microsoft
          </button>
        </div>
      );
    }
    if (this.state.userInfo) {
      templates.push(
        <pre key="userInfo">{JSON.stringify(this.state.userInfo, null, 4)}</pre>
      );
    }
    if (this.state.loginFailed) {
      templates.push(<strong key="loginFailed">Login unsuccessful</strong>);
    }
    if (this.state.apiCallFailed) {
      templates.push(
        <strong key="apiCallFailed">Graph API call unsuccessful</strong>
      );
    }
    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">React app with MSAL.js</h1>
        </header>
        {templates}
      </div>
    );
  }
}

export default App;

auth.service

import * as Msal from 'msal';

export default class AuthService {
  constructor() {
    let PROD_REDIRECT_URI = 'http://localhost:3000/';
    let redirectUri = window.location.origin;
    if (window.location.hostname !== '127.0.0.1') {
      redirectUri = PROD_REDIRECT_URI;
    }
    this.applicationConfig = {
      clientID: 'xxxx-xxxxx-xxxxx-xxxx',
      graphScopes: ['user.read','user.readbasic.all']
    };
    this.app = new Msal.UserAgentApplication(
      this.applicationConfig.clientID,
      '',
      () => {
        // callback for login redirect
      },
      {
        redirectUri
      }
    );
  }
  login = () => {
    return this.app.loginPopup(this.applicationConfig.graphScopes).then(
      idToken => {
        const user = this.app.getUser();
        if (user) {
          return user;
        } else {
          return null;
        }
      },
      () => {
        return null;
      }
    );
  };
  logout = () => {
    this.app.logout();
  };
  getToken = () => {
    return this.app.acquireTokenSilent(this.applicationConfig.graphScopes).then(
      accessToken => {
        return accessToken;
      },
      error => {
        return this.app
          .acquireTokenPopup(this.applicationConfig.graphScopes)
          .then(
            accessToken => {
              return accessToken;
            },
            err => {
              console.error(err);
            }
          );
      }
    );
  };
}

graph.service

export default class GraphService {
  constructor() {
    this.graphUrl = 'https://graph.microsoft.com/v1.0/users';
  }

  getUserInfo = token => {
    const headers = new Headers({ Authorization: `Bearer ${token}` });
    const options = {
      headers
    };
    return fetch(this.graphUrl, options)
      .then(response => response.json())
      .catch(response => {
        throw new Error(response);
      });
  };
}

hello.service

export default class HelloService {
  constructor() {
    this.graphUrl = 'https://xxx.azurewebsites.net/api/Hey';
  }

  callApi = token => {
    const headers = new Headers({ Authorization: `Bearer ${token}` });
    const options = {
      headers
    };
    return fetch(this.graphUrl, options)
      .then(response => response.json())
      .catch(response => {
        throw new Error(response);
      });
  };
}

调用此 hello.service 可以正常工作,但是在被Azure AD应用锁定时返回401。我还从jwt.io验证了JWT令牌。我猜测问题是身份验证问题(希望是一个简单的问题),根据应用程序是仅适用于Azure AD的应用程序还是融合的应用程序,会出现问题吗?我还在功能应用程序本身上启用了CORS。

我的大脑此时已冻结,我不确定朝哪个方向。任何帮助将不胜感激,谢谢。

0 个答案:

没有答案