在 react-admin 中添加无需身份验证的自定义页面

Adding custom page without authentication in react-admin

我想在我的 react-admin 门户网站中添加一个注册页面。由于 react-admin 不提供注册页面,我创建了一个自定义页面并将其添加到自定义路由中:

customRoutes.js

import React from 'react';
import { Route } from 'react-router-dom';
import SignupForm from './signupForm';

export default [
    <Route path="/signup" component={SignupForm} noLayout/>,
];

问题是当用户已经登录时,我只能在 /signup 打开页面。否则我会自动重定向到 /login 路由。

如何禁用自定义路由的身份验证? <Route> 是否接受某些属性或与 dataProvider.js 有关?

编辑

为我的 signupForm.js 添加代表代码:

import React from 'react';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import { fetchUtils } from 'react-admin';
import { ApiUrl } from './config';

class SignupForm extends React.Component {
    constructor() {
        super();
        this.state = {
            fields: {
                username: '',
                password: ''
            }
    }


    handleChange = name => event => {
        let fields = this.state.fields;
        fields[name] = event.target.value;

        this.setState({
            fields: fields,
        });
    };

    handleSubmit = (event) => {
        // Prevent default
        event.preventDefault();

        if (this.handleValidation()) {
            let body = JSON.parse(JSON.stringify(this.state.fields));

            let url = ApiUrl + '/api/user/create';
            let options = {}
            options.headers = new Headers({ Accept: 'application/json' });
            options.method = 'POST'
            options.body = JSON.stringify(body);
            fetchUtils.fetchJson(url, options)
                .then(data => {
                    alert(data.json.message);
                    this.props.history.push('/login')
                })
                .catch((err, ...rest) => {
                    console.log(err.status, err.message);
                    alert(err.message);
                });
        }
    }

    render() {
        const { classes } = this.props;

        const actions = [
            <Button
                type="submit"
                label="Submit"
                color='primary'
                variant="flat"
            >Submit</Button>,
        ];

        return (
            <Dialog
                open={true}
                style={{
                    textAlign: "center",
                }}
                onClose={this.handleClose}
                classes={{ paper: classes.dialogPaper }}
            >
                <DialogTitle>Create an Account</DialogTitle>
                <form className={classes.container} noValidate autoComplete="off" onSubmit={this.handleSubmit}>
                    <TextField
                        required
                        id="username"
                        label="Username"
                        value={this.state.fields["username"]}
                        onChange={this.handleChange('username')}
                    />
                    <br />
                    <TextField
                        required
                        id="password"
                        label="Password"
                        value={this.state.fields["password"]}
                        onChange={this.handleChange('password')}
                        type="password"
                    />

                    <div style={{ textAlign: 'right', padding: 40 }}>
                        {actions}
                    </div>
                </form>
            </Dialog>
        );
    }
}

export default withStyles(styles)(SignupForm);

问题是,根据 /signup 的请求,react-admin 正在调用类型为 AUTH_GET_PERMISSIONSauthProvider,其代码为:

if (type === AUTH_GET_PERMISSIONS) {
    const role = localStorage.getItem('role');
    return role ? Promise.resolve(role) : Promise.reject();
}

由于用户未登录,因此 localStorage.role 从未初始化。

更改为:

if (type === AUTH_GET_PERMISSIONS) {
    const role = localStorage.getItem('role');
    return role ? Promise.resolve(role) : Promise.resolve('guest');
}

React-admin V3版本,默认将authProvider改为return'guest'角色:

authProvider.js

  ...,
  getPermissions: () => {
    const role = localStorage.getItem('permissions')
    return role ? Promise.resolve(role) : Promise.resolve('guest') // default 'guest'
  },
  ...

现在您的 customRoutes pages will no longer redirect to /login, and you can use the usePermissions 钩子可以检查自定义页面中的角色。

您可以在 customRoutes.js 文件中使用所有未经身份验证的路由创建一个类似枚举的对象 PublicRoutes,如下所示:

customRoutes.js


export const PublicRoutes = {
    SIGNUP: "/signup",
}

export const customRoutes = [
     <Route path={PublicRoutes.SIGNUP} component={SignupForm} noLayout/>
]

然后在您的 authProvider 中导入 historyrouter 对象(在您的 Admin 组件中创建),以访问当前位置 pathname

接下来,创建一个函数表达式isPublicRoute,它将检查当前路由是否可以在不进行身份验证的情况下提供服务。 在 AUTH_GET_PERMISSIONS 和可选的 AUTH_CHECK 之上添加此检查(如果您在此处有例如 JWT 解析器)。

对于 AUTH_GET_PERMISSIONS return Promise.resolve() 因为我们有 public 路由的权限。对于 AUTH_CHECK return Promise.reject() 因为我们在这里不需要授权(例如获取或解析 JWT)。

authProvider.js


import {PublicRoutes} from "./customRoutes";

...

const isPublicRoute = (pathname) => Object.values(PublicRoutes).some(route => route === pathname);

...

const {pathname} = router.location;

if (type === AUTH_GET_PERMISSIONS) {
     // has to be on top 
     if(isPublicRoute(pathname)) return Promise.resolve();
     ...
}

if (type === AUTH_CHECK) {
     // has to be on top        
     if(isPublicRoute(pathname)) return Promise.reject()
     ...
}

在您的 authProvider 中,您应该有一个名为 checkAuth 的方法,如果 window.location.pathname 是 public 路由,则 returns Promise.resolve()

const publicRoutes = [
    '/appointment',
]

const authProvider: AuthProvider = {
    login: ({ username, password }) => {
    },
    checkAuth: () => {

        if (publicRoutes.includes(window.location.pathname)) {
            return Promise.resolve()
        }

        // your authentication endpoint / system
        // ...
    },
    getPermissions: () => {
    },
    logout: () => {
    },
    checkError: (error) => {
    },
    getIdentity: () => {
    },
};