В последней статье мы сосредоточились на создании контекста аутентификации и реализации регистрации. Теперь давайте пойдем дальше и добавим вход пользователя в систему, выход из системы и взглянем на сеанс пользователя.
Авторизоваться
Теперь, когда у нас есть зарегистрированный пользователь, пришло время предоставить ему возможность войти в систему.
Начнем с создания компонента Login с базовой разметкой. Мы можем начать с дублирования компонента SignUp и внесения нескольких изменений:
const Login = () => { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const handleSubmit = (event: FormEvent<HTMLFormElement>) => { event.preventDefault(); }; return ( <Flex minH={"100vh"} align={"center"} justify={"center"} bg={useColorModeValue("gray.50", "gray.800")} > <Stack spacing={8} mx={"auto"} maxW={"lg"} py={12} px={6}> <Stack align={"center"}> <Heading fontSize={"4xl"}>Login</Heading> </Stack> <Box rounded={"lg"} bg={useColorModeValue("white", "gray.700")} boxShadow={"lg"} p={8} > <form onSubmit={handleSubmit}> <Stack spacing={4}> <FormControl id="email"> <FormLabel>Email address</FormLabel> <Input type="email" onChange={(event) => setEmail(event.target.value)} /> </FormControl> <FormControl id="password"> <FormLabel>Password</FormLabel> <Input type="password" onChange={(event) => setPassword(event.target.value)} /> </FormControl> <Stack spacing={10}> <Button bg={"blue.400"} color={"white"} _hover={{ bg: "blue.500", }} type="submit" > Login </Button> </Stack> </Stack> </form> </Box> </Stack> </Flex> ); }; export default Login;
Теперь давайте создадим функцию для аутентификации пользователя. Мы можем добавить эту функцию в наш файл контекста:
const authenticate = useCallback( async (Username: string, Password: string) => { const user = new CognitoUser({ Username, Pool: UserPool, }); const authDetails = new AuthenticationDetails({ Username, Password, }); user.authenticateUser(authDetails, { onSuccess: (data) => { setSession(data); }, onFailure: (error) => { if (error) { toast({ title: error.message, status: "error", isClosable: true, }); } }, }); }, [toast] );
Далее давайте импортируем и вызываем эту функцию, когда пользователь отправляет форму входа:
// Login.tsx const handleSubmit = (event: FormEvent<HTMLFormElement>) => { event.preventDefault(); authenticate(email, password); };
Я столкнулся с ошибкой:
Причина ошибки в том, что требуется опция MFA (многофакторная аутентификация). Чтобы решить эту проблему, выполните следующие действия:
- Перейдите к настройкам пула пользователей.
- Перейдите в раздел «Вход в систему».
- Нажмите на опцию «Многофакторная аутентификация» и выберите «Изменить».
Когда вы окажетесь в настройках «Многофакторная аутентификация», у вас будет возможность выбрать предпочтительный метод аутентификации. Поскольку мне не нужен MFA для тестового приложения, я просто отключил его. Таким образом, вы можете продолжить тестирование без необходимости дополнительных шагов аутентификации.
Теперь мы можем попробовать войти снова:
Большой! Мы получили всю необходимую информацию для управления нашим пользователем. В следующем разделе я объясню, как получить сеанс пользователя, и покажу, как выйти из системы.
Сеанс пользователя
После авторизации получаем три вещи:
- токен доступа
- идентификатор токена
- обновить токен
Все это мы можем использовать для получения пользовательской сессии, содержащей информацию о пользователе.
Сначала я создаю функцию getSession
в контексте Auth:
// Auth.tsx const getSession: State["getSession"] = useCallback(async () => { return new Promise((resolve, reject) => { // 1. get current session after login const userSession = UserPool.getCurrentUser(); if (userSession) { userSession.getSession( async (error: unknown, session: CognitoUserSession) => { if (error) { console.error(error); } else { const attributes: { [key: string]: string } = await new Promise( (resolve, reject) => { // 2. if we have a session we can get user info userSession.getUserAttributes((error, attributes) => { if (error) { reject(error); } else { const results: { [key: string]: string } = {}; // 3. Normalize user info if (attributes) for (const attribute of attributes) { const { Name, Value } = attribute; results[Name] = Value; } resolve(results); } }); } ); const value = { session, attributes: attributes, }; // 4. Return user session and user info resolve(value); } } ); } else { reject(); } }); }, []);
Теперь, когда у нас есть функция getSession
, мы можем использовать ее после входа пользователя в систему. Вызывая эту функцию, мы можем получить сеанс пользователя и отобразить все необходимые данные для пользователя на странице его учетной записи. Итак, давайте создадим страницу аккаунта.
Чтобы страница «Учетная запись» отображалась только тогда, когда доступна сессия пользователя, нам нужно добавить условие в наш файл App.tsx
. Это гарантирует, что страница отображается только тогда, когда у нас есть действующий сеанс пользователя:
function App() { const { session } = useAuth(); return <>{session ? <Account /> : <Login />}</>; }
Далее приступим к созданию страницы Account
:
const Account = () => { const { getSession } = useAuth(); const [profile, setProfile] = useState<{ username: string; email: string; } | null>({ username: "", email: "", }); useEffect(() => { getSession().then((data) => { setProfile({ username: data.attributes.name, email: data.attributes.email, }); }); }, [getSession]); return ( <Flex minH={"100vh"} align={"center"} justify={"center"} bg={useColorModeValue("gray.50", "gray.800")} > <Stack spacing={4} w={"full"} maxW={"md"} bg={useColorModeValue("white", "gray.700")} rounded={"xl"} boxShadow={"lg"} p={6} my={12} > <Heading lineHeight={1.1} fontSize={{ base: "2xl", sm: "3xl" }}> User Profile </Heading> <FormControl id="userName"> <FormLabel>User name</FormLabel> <Input placeholder="UserName" _placeholder={{ color: "gray.500" }} type="text" disabled value={profile?.username} /> </FormControl> <FormControl id="email"> <FormLabel>Email address</FormLabel> <Input placeholder="[email protected]" _placeholder={{ color: "gray.500" }} type="email" disabled value={profile?.email} /> </FormControl> <Stack spacing={6} direction={["column", "row"]}> <Button bg={"red.400"} color={"white"} w="full" _hover={{ bg: "red.500", }} > Logout </Button> </Stack> </Stack> </Flex> ); };
Вот так выглядит страница Account
:
Здесь у нас есть простая форма, которая включает поля для имени пользователя и электронной почты, а также кнопку выхода. Это охватывает основы управления сеансом пользователя. Если вы заинтересованы в более глубоком изучении пользовательских сессий и пользовательских атрибутов, я рекомендую прочитать официальную документацию для получения более подробной информации.
Выйти
Выйти очень просто. Я создаю функцию выхода из системы в Auth.tsx
:
const logout = useCallback(() => { const user = UserPool.getCurrentUser(); if (user) { user.signOut(); setSession(null); } }, []);
и вызовите эту функцию, когда пользователь нажимает кнопку выхода из системы:
// Account.tsx <Button bg={"red.400"} color={"white"} w="full" _hover={{ bg: "red.500", }} onClick={logout} // <-- logout function from Auth.tsx > Logout </Button>
Это все для выхода из системы.
Давайте посмотрим, что мы сделали в этом разделе:
- Мы разрешили пользователям входить в наше приложение.
- Мы реализовали функциональность для получения сеанса пользователя и создали страницу «Учетная запись» для отображения пользовательских данных.
- Мы предоставили пользователям возможность выхода из своих учетных записей.
Надеюсь, вы хорошо провели время, просматривая эту статью! В следующей части нашей серии я покажу вам, как менять пароли и обновлять адреса электронной почты. До встречи в следующей статье!