Can authenticate using password
This commit is contained in:
parent
ae84ae8822
commit
fc1104ec89
@ -9,6 +9,13 @@ export enum CreateAccountResult {
|
|||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PasswordLoginResult {
|
||||||
|
TooManyRequests,
|
||||||
|
InvalidCredentials,
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
export interface CheckResetTokenResponse {
|
export interface CheckResetTokenResponse {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
@ -65,6 +72,40 @@ export class AuthApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate using an email and a password
|
||||||
|
*
|
||||||
|
* @param mail The email address to use
|
||||||
|
* @param password The password to use
|
||||||
|
*/
|
||||||
|
static async LoginWithPassword(
|
||||||
|
mail: string,
|
||||||
|
password: string
|
||||||
|
): Promise<PasswordLoginResult> {
|
||||||
|
const res = await APIClient.exec({
|
||||||
|
uri: "/auth/password_login",
|
||||||
|
method: "POST",
|
||||||
|
allowFail: true,
|
||||||
|
jsonData: {
|
||||||
|
mail: mail,
|
||||||
|
password: password,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (res.status) {
|
||||||
|
case 429:
|
||||||
|
return PasswordLoginResult.TooManyRequests;
|
||||||
|
case 401:
|
||||||
|
return PasswordLoginResult.InvalidCredentials;
|
||||||
|
case 200:
|
||||||
|
case 201:
|
||||||
|
sessionStorage.setItem(TokenStateKey, res.data.token);
|
||||||
|
return PasswordLoginResult.Success;
|
||||||
|
default:
|
||||||
|
return PasswordLoginResult.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start OpenID login
|
* Start OpenID login
|
||||||
*
|
*
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
import { Alert, CircularProgress } from "@mui/material";
|
import {
|
||||||
|
Alert,
|
||||||
|
CircularProgress,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
InputAdornment,
|
||||||
|
InputLabel,
|
||||||
|
OutlinedInput,
|
||||||
|
Tooltip,
|
||||||
|
} from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { AuthApi } from "../../api/AuthApi";
|
import { AuthApi, PasswordLoginResult } from "../../api/AuthApi";
|
||||||
import { ServerApi } from "../../api/ServerApi";
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import { VisibilityOff, Visibility } from "@mui/icons-material";
|
||||||
|
import { useSetAtom } from "jotai";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login form
|
* Login form
|
||||||
@ -16,13 +27,55 @@ export function LoginRoute(): React.ReactElement {
|
|||||||
const [loading, setLoading] = React.useState(false);
|
const [loading, setLoading] = React.useState(false);
|
||||||
const [error, setError] = React.useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
const setAuth = useSetAtom(AuthApi.authStatus);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [mail, setMail] = React.useState("");
|
||||||
|
const [password, setPassword] = React.useState("");
|
||||||
|
|
||||||
|
const canSubmit = mail.length > 0 && password.length > 0;
|
||||||
|
|
||||||
|
const [showPassword, setShowPassword] = React.useState(false);
|
||||||
|
const handleClickShowPassword = () => setShowPassword((show) => !show);
|
||||||
|
|
||||||
|
const handleMouseDownPassword = (
|
||||||
|
event: React.MouseEvent<HTMLButtonElement>
|
||||||
|
) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const data = new FormData(event.currentTarget);
|
};
|
||||||
console.log({
|
|
||||||
email: data.get("email"),
|
const handleLoginSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
password: data.get("password"),
|
event.preventDefault();
|
||||||
});
|
if (!canSubmit) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await AuthApi.LoginWithPassword(mail, password);
|
||||||
|
|
||||||
|
switch (res) {
|
||||||
|
case PasswordLoginResult.TooManyRequests:
|
||||||
|
setError(
|
||||||
|
"Trop de tentatives de connection. Veuillez réessayer ultérieurement."
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PasswordLoginResult.InvalidCredentials:
|
||||||
|
setError("Identifiants saisis invalides !");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PasswordLoginResult.Success:
|
||||||
|
navigate("/");
|
||||||
|
setAuth(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PasswordLoginResult.Error:
|
||||||
|
setError("Echec de la connexion !");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
setError("Echec de l'authentification !");
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const authWithProvider = async (id: string) => {
|
const authWithProvider = async (id: string) => {
|
||||||
@ -46,9 +99,7 @@ export function LoginRoute(): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{error === null ? (
|
{error && (
|
||||||
<></>
|
|
||||||
) : (
|
|
||||||
<Alert style={{ width: "100%" }} severity="error">
|
<Alert style={{ width: "100%" }} severity="error">
|
||||||
{error}
|
{error}
|
||||||
</Alert>
|
</Alert>
|
||||||
@ -57,7 +108,12 @@ export function LoginRoute(): React.ReactElement {
|
|||||||
<Typography component="h2" variant="body1">
|
<Typography component="h2" variant="body1">
|
||||||
Connexion
|
Connexion
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box component="form" noValidate onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
<Box
|
||||||
|
component="form"
|
||||||
|
noValidate
|
||||||
|
onSubmit={handleLoginSubmit}
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
>
|
||||||
<TextField
|
<TextField
|
||||||
margin="normal"
|
margin="normal"
|
||||||
required
|
required
|
||||||
@ -65,24 +121,47 @@ export function LoginRoute(): React.ReactElement {
|
|||||||
id="email"
|
id="email"
|
||||||
label="Adresse mail"
|
label="Adresse mail"
|
||||||
name="email"
|
name="email"
|
||||||
|
value={mail}
|
||||||
|
onChange={(e) => setMail(e.target.value)}
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<TextField
|
|
||||||
margin="normal"
|
<FormControl fullWidth variant="outlined">
|
||||||
|
<InputLabel htmlFor="password">Mot de passe</InputLabel>
|
||||||
|
<OutlinedInput
|
||||||
required
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
name="password"
|
name="password"
|
||||||
label="Mot de passe"
|
label="Mot de passe"
|
||||||
type="password"
|
type={showPassword ? "text" : "password"}
|
||||||
id="password"
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
|
endAdornment={
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<Tooltip title="Afficher le mot de passe">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={handleClickShowPassword}
|
||||||
|
onMouseDown={handleMouseDownPassword}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{ mt: 3, mb: 2 }}
|
sx={{ mt: 3, mb: 2 }}
|
||||||
|
disabled={!canSubmit}
|
||||||
>
|
>
|
||||||
Connexion
|
Connexion
|
||||||
</Button>
|
</Button>
|
||||||
@ -117,7 +196,7 @@ export function LoginRoute(): React.ReactElement {
|
|||||||
style={{ textAlign: "center", width: "100%", marginTop: "20px" }}
|
style={{ textAlign: "center", width: "100%", marginTop: "20px" }}
|
||||||
onClick={() => authWithProvider(p.id)}
|
onClick={() => authWithProvider(p.id)}
|
||||||
>
|
>
|
||||||
Connection avec {p.name}
|
Connexion avec {p.name}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user