1.根据路由信息可知用户的权限控制

  1. //layouts/SecurityLayout.tsx
  2. import React from 'react';
  3. import { PageLoading } from '@ant-design/pro-layout';
  4. import type { ConnectProps } from 'umi';
  5. import { Redirect, connect } from 'umi';
  6. import { stringify } from 'querystring';
  7. import type { ConnectState } from '@/models/connect';
  8. import type { CurrentUser } from '@/models/user';
  9. type SecurityLayoutProps = {
  10. loading?: boolean;
  11. currentUser?: CurrentUser;
  12. } & ConnectProps;
  13. type SecurityLayoutState = {
  14. isReady: boolean;
  15. };
  16. class SecurityLayout extends React.Component<SecurityLayoutProps, SecurityLayoutState> {
  17. state: SecurityLayoutState = {
  18. isReady: false,
  19. };
  20. componentDidMount() {
  21. this.setState({
  22. isReady: true,
  23. });
  24. const { dispatch } = this.props;
  25. if (dispatch) {
  26. //获取用户信息,触发model中的方法
  27. dispatch({
  28. type: 'user/fetchCurrent',
  29. });
  30. }
  31. }
  32. render() {
  33. const { isReady } = this.state;
  34. //从这里可以看出props中获取用户的信息,这里的props是在model中
  35. const { children, loading, currentUser } = this.props;
  36. //根据是否登录进行跳转,这里deid是发送请求后获取的数据
  37. const isLogin = currentUser && currentUser.id;
  38. const queryString = stringify({
  39. redirect: window.location.href,
  40. });
  41. if ((!isLogin && loading) || !isReady) {
  42. return <PageLoading />;
  43. }
  44. if (!isLogin && window.location.pathname !== '/login') {
  45. return <Redirect to={`/login?${queryString}`} />;
  46. }
  47. return children;
  48. }
  49. }
  50. export default connect(({ user, loading }: ConnectState) => ({
  51. currentUser: user.currentUser,
  52. loading: loading.models.user,
  53. }))(SecurityLayout);

2.在model中获取用户信息

  1. import type { Effect, Reducer } from 'umi';
  2. import { queryCurrent, query as queryUsers } from '@/services/user';
  3. //定义用户信息的类型
  4. export type CurrentUser = {
  5. avatar_url?: string;
  6. name?: string;
  7. title?: string;
  8. group?: string;
  9. signature?: string;
  10. tags?: {
  11. key: string;
  12. label: string;
  13. }[];
  14. userid?: string;
  15. unreadCount?: number;
  16. };
  17. export type UserModelState = {
  18. currentUser?: CurrentUser;
  19. };
  20. //定义redux的类型
  21. export type UserModelType = {
  22. namespace: 'user';
  23. state: UserModelState;
  24. effects: {
  25. fetch: Effect;
  26. fetchCurrent: Effect;
  27. };
  28. reducers: {
  29. saveCurrentUser: Reducer<UserModelState>;
  30. changeNotifyCount: Reducer<UserModelState>;
  31. };
  32. };
  33. const UserModel: UserModelType = {
  34. namespace: 'user',
  35. state: {
  36. currentUser: {},
  37. },
  38. effects: {
  39. *fetch(_, { call, put }) {
  40. const response = yield call(queryUsers);
  41. yield put({
  42. type: 'save',
  43. payload: response,
  44. });
  45. },
  46. //判断本地的lacolstorage中是否有数据,如果有,则不需要再次发送请求,如果没有则发送请求并且将请求结果保存到本地缓存中
  47. *fetchCurrent(_, { call, put }) {
  48. //查看本地的localstorage是否有用户信息,没有在请求
  49. const userInfo = localStorage.getItem('useInfo');
  50. let response = null;
  51. if (!userInfo) {
  52. //获取用户信息
  53. response = yield call(queryCurrent);
  54. console.log( response);
  55. //把用户数据存入缓存
  56. localStorage.setItem('userInfo', JSON.stringify(response));
  57. } else {
  58. response = JSON.parse(userInfo);
  59. }
  60. yield put({
  61. type: 'saveCurrentUser',
  62. payload: response,
  63. });
  64. },
  65. },
  66. reducers: {
  67. saveCurrentUser(state, action) {
  68. return {
  69. ...state,
  70. currentUser: action.payload || {},
  71. };
  72. },
  73. changeNotifyCount(
  74. state = {
  75. currentUser: {},
  76. },
  77. action,
  78. ) {
  79. return {
  80. ...state,
  81. currentUser: {
  82. ...state.currentUser,
  83. notifyCount: action.payload.totalCount,
  84. unreadCount: action.payload.unreadCount,
  85. },
  86. };
  87. },
  88. },
  89. };
  90. export default UserModel;

3.发送请求获取用户信息

  1. //services/user.ts
  2. import request from '@/utils/request';
  3. export async function queryCurrent(): Promise<any> {
  4. return request('/admin/user');
  5. }

4.在登录组件的生命周期中根据缓存中是否有登录信息来判断是否重定向到首页

  1. //page/login/index.tsx
  2. useEffect(() => {
  3. //判断用户是否登录,如果登录则重定向到首页
  4. const userInfo=localStorage.getItem('userInfo')
  5. if(userInfo) history.replace('/')
  6. }, [])

5.根据缓存的用户信息去设置首页头部

  1. //src/components/GlobalHeader/AvatarDropdown.tsx
  2. import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
  3. import { Avatar, Menu, Spin } from 'antd';
  4. import React from 'react';
  5. import type { ConnectProps } from 'umi';
  6. import { history, connect } from 'umi';
  7. import type { ConnectState } from '@/models/connect';
  8. import type { CurrentUser } from '@/models/user';
  9. import HeaderDropdown from '../HeaderDropdown';
  10. import styles from './index.less';
  11. export type GlobalHeaderRightProps = {
  12. currentUser?: CurrentUser;
  13. menu?: boolean;
  14. } & Partial<ConnectProps>;
  15. class AvatarDropdown extends React.Component<GlobalHeaderRightProps> {
  16. onMenuClick = (event: {
  17. key: React.Key;
  18. keyPath: React.Key[];
  19. item: React.ReactInstance;
  20. domEvent: React.MouseEvent<HTMLElement>;
  21. }) => {
  22. const { key } = event;
  23. if (key === 'logout') {
  24. const { dispatch } = this.props;
  25. if (dispatch) {
  26. dispatch({
  27. type: 'login/logout',
  28. });
  29. }
  30. return;
  31. }
  32. history.push(`/account/${key}`);
  33. };
  34. render(): React.ReactNode {
  35. const {
  36. currentUser = {
  37. avatar_url: '',
  38. name: '',
  39. },
  40. menu,
  41. } = this.props;
  42. const menuHeaderDropdown = (
  43. <Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
  44. {menu && (
  45. <Menu.Item key="center">
  46. <UserOutlined />
  47. 个人中心
  48. </Menu.Item>
  49. )}
  50. {menu && (
  51. <Menu.Item key="settings">
  52. <SettingOutlined />
  53. 个人设置
  54. </Menu.Item>
  55. )}
  56. {menu && <Menu.Divider />}
  57. <Menu.Item key="logout">
  58. <LogoutOutlined />
  59. 退出登录
  60. </Menu.Item>
  61. </Menu>
  62. );
  63. return currentUser && currentUser.name ? (
  64. // 这里是设置头部
  65. <HeaderDropdown overlay={menuHeaderDropdown}>
  66. <span className={`${styles.action} ${styles.account}`}>
  67. <Avatar size="small" className={styles.avatar} src={currentUser.avatar_url} alt="avatar" />
  68. <span className={`${styles.name} anticon`}>{currentUser.name}</span>
  69. </span>
  70. </HeaderDropdown>
  71. ) : (
  72. <span className={`${styles.action} ${styles.account}`}>
  73. <Spin
  74. size="small"
  75. style={{
  76. marginLeft: 8,
  77. marginRight: 8,
  78. }}
  79. />
  80. </span>
  81. );
  82. }
  83. }
  84. export default connect(({ user }: ConnectState) => ({
  85. currentUser: user.currentUser,
  86. }))(AvatarDropdown);