Make the login form pluggable

Allow extending the login form with additional authentication methods by
adding them to the web plugin's loginForms array.
This commit is contained in:
Hornwitser committed 2021-03-13 21:01:53 +01:00
1 parent 579f6421e4
commit ceae2b25b5
3 files changed
+66 -13

No files matched your search

+22
View File
@@ -424,6 +424,21 @@ class BaseControlPlugin {
}
/**
* Plugin supplied login form
* @typedef {Object} module:lib/plugin~LoginForm
* @property {string} name -
* Internal name of the login form, this should start with the
* plugin name followed by a dot.
* @property {string} title -
* Name displayed above this form in the login window.
* @property {React.Component} Component -
* React component that's rendered for this login form. This is
* supplied the setToken function via its props which should be
* called when an authentication token is aquired via this
* form.
*/
/**
* Base class for web interface plugins
*
@@ -455,6 +470,13 @@ class BaseWebPlugin {
* `error`, `warn`, `audit`, `info` and `verbose`.
*/
this.logger = logger.child({ plugin: this.info.name });
/**
* List of login forms provided by this plugin
*
* @type {Array<module:lib/plugin~LoginForm>}
*/
this.loginForms = [];
}
/**
+1 -4
View File
@@ -81,10 +81,7 @@ export default function App(props) {
} else {
page = <div className="login-container">
<Card>
<h1>Clusterio</h1>
<LoginForm setToken={setToken} />
</Card>
<LoginForm setToken={setToken} />
</div>;
}
+43 -9
View File
@@ -1,27 +1,61 @@
import React from "react";
import { Form, Input, Button } from "antd";
import React, { Fragment, useContext } from "react";
import { Button, Card, Divider, Form, Image, Input, List, Space, Spin, Typography } from "antd";
import LockOutlined from "@ant-design/icons/LockOutlined";
export default function LoginForm(props) {
return (
import logo from "../images/logo.png";
import PluginsContext from "./PluginsContext";
const { Paragraph, Text } = Typography;
function TokenAuth(props) {
return <>
<Paragraph>If you have generated an authentication token from the master server, use that here.</Paragraph>
<Form
name="login"
onFinish={(values) => { props.setToken(values.token); }}
layout="inline"
>
<Form.Item
name="token"
rules={[
{ required: true, message: "Please input authentication token" },
]}
rules={[{ required: true }]}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
style={{ width: "14em" }}
prefix=<LockOutlined className="site-form-item-icon" />
type="password"
placeholder="Authentication Token"
/>
</Form.Item>
<Button type="primary" htmlType="submit">Log in</Button>
</Form>
);
</>;
}
export default function LoginForm(props) {
let plugins = useContext(PluginsContext);
let loginForms = [];
for (let plugin of plugins.values()) {
loginForms.push(...plugin.loginForms);
}
loginForms.push({
name: "core.token",
title: "Token",
Component: TokenAuth,
});
return <Card style={{ maxWidth: "30em" }}>
<Space style={{ width: "100%" }} direction="vertical" align="center">
<h1>Clusterio</h1>
<Image width={128} height={123} src={logo} />
Log in to the cluster using one of the methods below.
</Space>
{loginForms.map(form => <Fragment key={form.name}>
<Divider orientation="center">{form.title}</Divider>
<form.Component setToken={props.setToken} />
</Fragment>)}
</Card>;
}