Как получить текущие роли пользователя с ADAL JS - PullRequest
0 голосов
/ 29 мая 2018

У меня есть следующее приложение реагирования, которое является шаблоном от envato.Я интегрировал аутентификацию Azure AD с использованием этого компонента, и он прекрасно работает:

https://github.com/salvoravida/react-adal

Однако я хочу создать РОЛИ и хочу показать пункты меню набоковая панель в зависимости от ролей текущего пользователя.

Я уже знаю, как создавать роли в Azure AD с помощью манифеста приложения, поэтому этот вопрос больше о том, как получить эти роли после аутентификации пользователя и какотображать пункты меню в зависимости от значения претензии.

Соответствующие фрагменты кода здесь:

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import DashApp from './dashApp';
import registerServiceWorker from './registerServiceWorker';
import 'antd/dist/antd.css';
import { runWithAdal } from 'react-adal';
import { authContext } from './adalConfig';

const DO_NOT_LOGIN = false;
runWithAdal(authContext, () => {
  ReactDOM.render(<DashApp />, document.getElementById('root'));
  // Hot Module Replacement API
  if (module.hot) {
    module.hot.accept('./dashApp.js', () => {
      const NextApp = require('./dashApp').default;
      ReactDOM.render(<NextApp />, document.getElementById('root'));
    });
  }

},DO_NOT_LOGIN);

registerServiceWorker();

AdalConfig.js

import {AuthenticationContext, adalFetch, withAdalLogin} из'act-adal ';

export const adalConfig = {
  tenant: 'abc-af96-4f7c-82db-b6f0bd7ae9b6',
  clientId: 'abc-969c-49b2-8a58-78eece990daf',
  endpoints: {
    api:'abc-083c-4c10-b40f-f1d764319b21'

  'apiUrl': 'https://abc.azurewebsites.net/api',
  cacheLocation: 'localStorage'
};

export const authContext = new AuthenticationContext(adalConfig);

export const adalApiFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.api, fetch, adalConfig.apiUrl+url, options);

export const withAdalLoginApi = withAdalLogin(authContext, adalConfig.endpoints.api);

dashboard.js

import React, { Component } from 'react';
import LayoutContentWrapper from '../components/utility/layoutWrapper';
import LayoutContent from '../components/utility/layoutContent';

export default class extends Component {
  render() {
    return (
      <LayoutContentWrapper style={{ height: '100vh' }}>
        <LayoutContent>
          <h1>ISOMORPHIC DASHBOARD HOME</h1>
        </LayoutContent>
      </LayoutContentWrapper>
    );
  }
}

Router.js

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import { connect } from 'react-redux';

import App from './containers/App/App';
import asyncComponent from './helpers/AsyncFunc';

const RestrictedRoute = ({ component: Component, isLoggedIn, ...rest }) => (
  <Route
    {...rest}
    render={props => isLoggedIn
      ? <Component {...props} />
      : <Redirect
          to={{
            pathname: '/signin',
            state: { from: props.location },
          }}
        />}
  />
);

const PublicRoutes = ({ history, isLoggedIn }) => {
  return (
    <ConnectedRouter history={history}>
      <div>
        <Route
          exact
          path={'/'}
          render={() => <Redirect to="/dashboard" />}
        />
        <Route
          exact
          path={'/signin'}
          component={asyncComponent(() => import('./containers/Page/signin'))}
        />
        <RestrictedRoute
          path="/dashboard"
          component={App}
          isLoggedIn={isLoggedIn}
        />
      </div>
    </ConnectedRouter>
  );
};


export default connect(state => ({
  isLoggedIn: state.Auth.get('idToken') !== null,
}))(PublicRoutes);

боковая панель

import React, { Component } from "react";
import { connect } from "react-redux";
import clone from "clone";
import { Link } from "react-router-dom";
import { Layout } from "antd";
import options from "./options";
import Scrollbars from "../../components/utility/customScrollBar.js";
import Menu from "../../components/uielements/menu";
import IntlMessages from "../../components/utility/intlMessages";
import SidebarWrapper from "./sidebar.style";
import appActions from "../../redux/app/actions";
import Logo from "../../components/utility/logo";
import themes from "../../settings/themes";
import { themeConfig } from "../../settings";

const SubMenu = Menu.SubMenu;
const { Sider } = Layout;

const {
  toggleOpenDrawer,
  changeOpenKeys,
  changeCurrent,
  toggleCollapsed
} = appActions;
const stripTrailingSlash = str => {
  if (str.substr(-1) === "/") {
    return str.substr(0, str.length - 1);
  }
  return str;
};

class Sidebar extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.onOpenChange = this.onOpenChange.bind(this);
  }
  handleClick(e) {
    this.props.changeCurrent([e.key]);
    if (this.props.app.view === "MobileView") {
      setTimeout(() => {
        this.props.toggleCollapsed();
        this.props.toggleOpenDrawer();
      }, 100);
    }
  }
  onOpenChange(newOpenKeys) {
    const { app, changeOpenKeys } = this.props;
    const latestOpenKey = newOpenKeys.find(
      key => !(app.openKeys.indexOf(key) > -1)
    );
    const latestCloseKey = app.openKeys.find(
      key => !(newOpenKeys.indexOf(key) > -1)
    );
    let nextOpenKeys = [];
    if (latestOpenKey) {
      nextOpenKeys = this.getAncestorKeys(latestOpenKey).concat(latestOpenKey);
    }
    if (latestCloseKey) {
      nextOpenKeys = this.getAncestorKeys(latestCloseKey);
    }
    changeOpenKeys(nextOpenKeys);
  }
  getAncestorKeys = key => {
    const map = {
      sub3: ["sub2"]
    };
    return map[key] || [];
  };
  getMenuItem = ({ singleOption, submenuStyle, submenuColor }) => {
    const { key, label, leftIcon, children } = singleOption;
    const url = stripTrailingSlash(this.props.url);
    if (children) {
      return (
        <SubMenu
          key={key}
          title={
            <span className="isoMenuHolder" style={submenuColor}>
              <i className={leftIcon} />
              <span className="nav-text">
                <IntlMessages id={label} />
              </span>
            </span>
          }
        >
          {children.map(child => {
            const linkTo = child.withoutDashboard
              ? `/${child.key}`
              : `${url}/${child.key}`;
            return (
              <Menu.Item style={submenuStyle} key={child.key}>
                <Link style={submenuColor} to={linkTo}>
                  <IntlMessages id={child.label} />
                </Link>
              </Menu.Item>
            );
          })}
        </SubMenu>
      );
    }
    return (
      <Menu.Item key={key}>
        <Link to={`${url}/${key}`}>
          <span className="isoMenuHolder" style={submenuColor}>
            <i className={leftIcon} />
            <span className="nav-text">
              <IntlMessages id={label} />
            </span>
          </span>
        </Link>
      </Menu.Item>
    );
  };
  render() {
    const { app, toggleOpenDrawer, height } = this.props;
    const collapsed = clone(app.collapsed) && !clone(app.openDrawer);
    const { openDrawer } = app;
    const mode = collapsed === true ? "vertical" : "inline";
    const onMouseEnter = event => {
      if (openDrawer === false) {
        toggleOpenDrawer();
      }
      return;
    };
    const onMouseLeave = () => {
      if (openDrawer === true) {
        toggleOpenDrawer();
      }
      return;
    };
    const customizedTheme = themes[themeConfig.theme];
    const styling = {
      backgroundColor: customizedTheme.backgroundColor
    };
    const submenuStyle = {
      backgroundColor: "rgba(0,0,0,0.3)",
      color: customizedTheme.textColor
    };
    const submenuColor = {
      color: customizedTheme.textColor
    };
    return (
      <SidebarWrapper>
        <Sider
          trigger={null}
          collapsible={true}
          collapsed={collapsed}
          width="240"
          className="isomorphicSidebar"
          onMouseEnter={onMouseEnter}
          onMouseLeave={onMouseLeave}
          style={styling}
        >
          <Logo collapsed={collapsed} />
          <Scrollbars style={{ height: height - 70 }}>
            <Menu
              onClick={this.handleClick}
              theme="dark"
              className="isoDashboardMenu"
              mode={mode}
              openKeys={collapsed ? [] : app.openKeys}
              selectedKeys={app.current}
              onOpenChange={this.onOpenChange}
            >
              {options.map(singleOption =>
                this.getMenuItem({ submenuStyle, submenuColor, singleOption })
              )}
            </Menu>
          </Scrollbars>
        </Sider>
      </SidebarWrapper>
    );
  }
}

export default connect(
  state => ({
    app: state.App.toJS(),
    height: state.App.toJS().height
  }),
  { toggleOpenDrawer, changeOpenKeys, changeCurrent, toggleCollapsed }
)(Sidebar);

Да, я знаю, что код слишком длинный, но я думаю, что имеет смысл дать хороший контекст для того, чтобы вопрос был ответственным.

Реактор-упаковщик из salvarovida использует вкапот библиотеки Adal JS,так что в основном это оболочка.

Очевидно, что с этой строкой кода можно получить роли, но не уверен, как ее использовать и где.

https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/713

1 Ответ

0 голосов
/ 10 апреля 2019

Поскольку вы упомянули, что вы создадите роли Azure AD, вы также можете добавлять пользователей / группы в эти роли.

См. Добавление ролей приложений в рекламных приложениях Azure.

После сопоставления этих ролей с пользователем вы можете запросить Graph API для пользователя.

GET https://graph.microsoft.com/v1.0/me

Это будет возвращать ответ как

HTTP/1.1 200 OK
Content-type: application/json
Content-length: 491
{

   "displayName": "displayName-value",
   "givenName": "givenName-value",
   "mail": "mail-value",
   "surname": "surname-value",
   "userPrincipalName": "userPrincipalName-value",
   "id": "id-value"
}

Теперь вы можете запросить Graph API для получения ролей, связанных с этим пользователем

POST /groups/{id}/getMemberGroups

Ответ будет содержать список всех сопоставленных групппользователю.Вы можете сохранить вновь созданные группы / роли, созданные вами в web.config, и проверить, являются ли они частью возвращаемого списка.

Примечание. Вам необходимы разрешения для Directory.Read.All, Directory.ReadWrite.Все, Directory.AccessAsUser.All, прежде чем вы сможете сделать этот вызов.

Источник: https://docs.microsoft.com/en-us/graph/api/user-list-memberof?view=graph-rest-1.0

Вы можете сделать эти вызовы API, используя либо Web API, либо JS.Я предпочитаю использовать WebAPI для извлечения ролей и возврата этих ролей в вызове API (для извлечения меню, установки разрешений и т. Д.) Также во внешнем интерфейсе.

Также см. https://graphexplorer.azurewebsites.net/ для тестирования этих вызовов перед их реализацией в коде.

Если вы хотите получить образец приложения, посмотрите это - Авторизация в веб-приложении с использованием ролей приложений Azure AD и утверждений о ролях

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...