未处理的拒绝(ClientAuthError):需要用户登录。对于静默调用,请求必须包含 sid 或 login_hint

use*_*001 8 reactjs react-aad-msal

我正在 React 中制作一个应用程序并使用“react-aad-msal”库(https://www.npmjs.com/package/react-aad-msal),该库使用 AzureAD 进行身份验证和授权,然后接收数据(从 API 列出任务)(正如我所举的例子https://github.com/Azure-Samples/ms-identity-javascript-angular-spa-dotnetcore-webapi-roles-groups/tree/master/chapter2/TodoListAPI)。我有以下组件:authProvider.js、TodoConstants.js、TodoActions.js、TodoReducer.js、TodoContainer.js、TodoSaga.js。当我添加 const token = wait authProvider.getAccessToken () 来从 TodoSaga.js 中的 API 请求数据时,我开始收到错误:未处理的拒绝 (ClientAuthError):需要用户登录。对于静默调用,请求必须包含 sid 或 login_hint。如果您在authProvider.js的authenticationParameters中添加loginHint: "myMail@domain.com",那么它就会开始正常工作并直接进入身份验证阶段,但如何正确指定loginHint或sid尚不清楚。请告诉我在这种情况下如何正确获取loginHint或sid?哪个参数更可取?

authProvider.js

import { MsalAuthProvider, LoginType } from "react-aad-msal";
import { Logger, LogLevel } from "msal";

const config = {
  auth: {
    clientId: "xxxx-xxxx-xxxx-xxxx",
    authority:
      "https://login.microsoftonline.com/yyyy-yyyy-yyyy-yyyy",
    validateAuthority: true,
    redirectUri: "http://localhost:3000",
    postLogoutRedirectUri: "http://localhost:3000",
    navigateToLoginRequestUrl: true,
  },
  cache: {
    cacheLocation: "localStorage",
    storeAuthStateInCookie: true,
  },
};

const authenticationParameters = {
  scopes: [
    "openid",
    "profile",
    "api://iiii-iiii-iiii-iiii/access_as_user",
  ],
  // loginHint: loginHint, <---- How to get it correctly?
  // sid: sid, <---- How to get it correctly?
};

const options = {
  loginType: LoginType.Popup,
  tokenRefreshUri: window.location.origin + "/auth.html",
};

export const authProvider = new MsalAuthProvider(
  config,
  authenticationParameters,
  options
);
Run Code Online (Sandbox Code Playgroud)

TodoConstants.js

export const TODODATASOURCE_API_CALL_REQUEST = "TODODATASOURCE_API_CALL_REQUEST";
export const TODODATASOURCE_API_CALL_SUCCESS = "TODODATASOURCE_API_CALL_SUCCESS";
export const TODODATASOURCE_API_CALL_FAILURE = "TODODATASOURCE_API_CALL_FAILURE";
Run Code Online (Sandbox Code Playgroud)

TodoActions.js

import * as types from "./TodoConstants";

export const fetchTodoDataSourceRequest = () => {
  return {
    type: types.TODODATASOURCE_API_CALL_REQUEST
  };
};

export const fetchTodoDataSourceSuccess = response => {
  return {
    type: types.TODODATASOURCE_API_CALL_SUCCESS,
    data: response,
  };
};

export const fetchTodoDataSourceFail = () => {
  return {
    type: types.TODODATASOURCE_API_CALL_FAILURE
  };
};
Run Code Online (Sandbox Code Playgroud)

TodoReducer.js

import * as types from "./TodoConstants";

const initialState = {
  fetching: false,
  data: null,
  error: null,
};

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case types.TODODATASOURCE_API_CALL_REQUEST:
      return { ...state, fetching: true, error: null };
    case types.TODODATASOURCE_API_CALL_SUCCESS:
      return {
        ...state,
        fetching: false,
        data: action.data,
      };
    case types.TODODATASOURCE_API_CALL_FAILURE:
      return {
        ...state,
        fetching: false,
        data: null,
        error: action.error
      };

    default:
      return state;
  }
}
Run Code Online (Sandbox Code Playgroud)

TodoContainer.js

import React from "react";
import TodoView from "../../views/TodoView";
import { connect } from "react-redux";
import * as actions from "./TodoActions";
// import { bindActionCreators } from "redux";
import { bindActionCreators } from "redux";

class TodoDataSourceContainer extends React.PureComponent {
  componentDidMount() {
    this.props.fetchTodoDataSourceRequest();
  }
  render() {
    return (
      <React.Fragment>
        <TodoDataSourceView {...this.props} />
      </React.Fragment>
    );
  }
}

const mapStateToProps = ({
  TodoDataSourceContainerReducerState: { fetching, data, error},
}) => {
  return {
    fetching: fetching,
    data: data,
    error: error,
  };
};

const mapDispatchToProps = (dispatch) => {
  const {
    fetchTodoDataSourceRequest: fetchTodoDataSourceRequest,
  } = bindActionCreators(actions, dispatch);
  return {
    fetchTodoDataSourceRequest: fetchTodoDataSourceRequest,
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoDataSourceContainer);
Run Code Online (Sandbox Code Playgroud)

TodoSaga.js

import { takeLatest, call, put } from "redux-saga/effects";
import * as types from "./TodoConstants";
import * as actions from "./TodoActions";
import { authProvider } from "../../../utils/Auth/authProvider";

const request = async (url) => {
  const token = await authProvider.getAccessToken(); // <---- After adding this, an error appears and the need for loginHint or sid

  const response = await fetch(url, {
    method: "GET",
    headers: {
      Authorization: "Bearer " + token.accessToken,
      "Content-Type": "application/json",
    },
  });

  if (response.ok) {
    let result = await response.json();
    return result;
  } else {
    alert("Error HTTP: " + response.status);
  }
};

export default function* watcherSaga() {
  yield takeLatest(types.TODODATASOURCE_API_CALL_REQUEST, workerSaga);
}

function* workerSaga() {
  try {
    const response = yield request("https://localhost:44351/api/todolist");
    yield put(actions.fetchTodoDataSourceSuccess(response));
  } catch (error) {
    yield put(actions.fetchTodoDataSourceFail(error));
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

bar*_*ost 0

阅读https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow

您可以使用此参数预填写用户登录页面的用户名和电子邮件地址字段。在从之前的登录中提取了 login_hint 可选声明后,应用程序可以在重新身份验证期间使用此参数。

因此,只需将 login_hint 设置为 your-mail@domain.com 或您公司常用的电子邮件模式即可。