Add support for authentication

This commit is contained in:
Pierre HUBERT 2023-09-04 14:20:48 +02:00
parent 8defc104c6
commit 44d565c6da
4 changed files with 169 additions and 6 deletions

View File

@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>VirtWeb</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,6 +1,6 @@
{ {
"short_name": "React App", "short_name": "VirtWeb",
"name": "Create React App Sample", "name": "Virtual machines management",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",

View File

@ -37,7 +37,6 @@ export class AuthApi {
await APIClient.exec({ await APIClient.exec({
uri: "/auth/local", uri: "/auth/local",
method: "POST", method: "POST",
allowFail: true,
jsonData: { jsonData: {
username: username, username: username,
password: password, password: password,

View File

@ -1,3 +1,167 @@
export function LoginRoute() { import { Visibility, VisibilityOff } from "@mui/icons-material";
return <></>; import {
Alert,
CircularProgress,
FormControl,
IconButton,
InputAdornment,
InputLabel,
OutlinedInput,
Tooltip,
} from "@mui/material";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Grid from "@mui/material/Grid";
import TextField from "@mui/material/TextField";
import Typography from "@mui/material/Typography";
import * as React from "react";
import { Link, useNavigate } from "react-router-dom";
import { useAuth } from "../../App";
import { AuthApi } from "../../api/AuthApi";
import { ServerApi } from "../../api/ServerApi";
/**
* Login form
*/
export function LoginRoute(): React.ReactElement {
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
const auth = useAuth();
const navigate = useNavigate();
const [username, setUsername] = React.useState("");
const [password, setPassword] = React.useState("");
const canSubmit = username.length > 0 && password.length > 0;
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
const handleLoginSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!canSubmit) return;
try {
await AuthApi.LoginWithPassword(username, password);
navigate("/");
auth.setSignedIn(true);
} catch (e) {
console.error(e);
setError("Auth failed!");
}
setLoading(false);
};
const authWithOpenID = async () => {
try {
setLoading(true);
const res = await AuthApi.StartOpenIDLogin();
window.location.href = res.url;
} catch (e) {
console.error(e);
setError("Failed to initialize OpenID login");
}
};
if (loading)
return (
<>
<CircularProgress />
</>
);
return (
<>
{error && (
<Alert style={{ width: "100%" }} severity="error">
{error}
</Alert>
)}
{ServerApi.Config.local_auth_enabled && (
<>
<Typography component="h2" variant="body1">
Local authentication
</Typography>
<Box
component="form"
noValidate
onSubmit={handleLoginSubmit}
sx={{ mt: 1 }}
>
<TextField
margin="normal"
required
fullWidth
id="username"
label="Username"
name="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
autoComplete="username"
autoFocus
/>
<FormControl fullWidth variant="outlined">
<InputLabel htmlFor="password">Password</InputLabel>
<OutlinedInput
required
fullWidth
name="password"
label="Password"
type={showPassword ? "text" : "password"}
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="current-password"
endAdornment={
<InputAdornment position="end">
<Tooltip title="Show password">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</Tooltip>
</InputAdornment>
}
/>
</FormControl>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
disabled={!canSubmit}
>
Login
</Button>
</Box>
</>
)}
<div>
{ServerApi.Config.oidc_auth_enabled && (
<Button
style={{ textAlign: "center", width: "100%", marginTop: "20px" }}
onClick={() => authWithOpenID()}
>
Authenticate using OpenID
</Button>
)}
</div>
</>
);
} }