-
Notifications
You must be signed in to change notification settings - Fork 4
Improve authorisation #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export const localStorageKey = 'token'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this key is used for authentication only, please define more specified variable name for the variable, like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, good idea! |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,9 +6,10 @@ import { | |
| authenticationReducer, | ||
| type AuthenticationReducer, | ||
| } from './authenticationReducer.ts'; | ||
| import { localStorageKey } from '../constants.ts'; | ||
|
|
||
| export const AuthenticationContext = createContext<Authentication>({ | ||
| token: "", | ||
| token: '', | ||
| }); | ||
| export const TokenDispatchContext = createContext<React.Dispatch<TokenAction>>( | ||
| {} as React.Dispatch<TokenAction> | ||
|
|
@@ -18,26 +19,31 @@ export const useAuthenticationData = () => useContext(AuthenticationContext); | |
| export const useTokenDispatch = () => useContext(TokenDispatchContext); | ||
|
|
||
| const AuthProvider = ({ children }: { children: React.ReactNode }) => { | ||
| const localStorageKey = 'token'; | ||
| const navigate = useNavigate(); | ||
|
|
||
| const [authentication, dispatch] = useReducer<AuthenticationReducer>( | ||
| authenticationReducer, | ||
| { | ||
| token: "" | ||
| } | ||
| { | ||
| token: '', | ||
| } | ||
| ); | ||
|
|
||
| useEffect(() => { | ||
| if (authentication.token) { | ||
| axios.defaults.headers.common['Authorization'] = | ||
| 'Bearer ' + authentication.token; | ||
| localStorage.setItem(localStorageKey, authentication.token); | ||
| console.log('Have token'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove all the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks! |
||
| } else if (localStorage.getItem(localStorageKey)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we shouldn't access the localStorage directly. The data from localStorage should be copied into the reducer's state once the page loads, and then you should only use the state. You can add an action like The approach should be:
This way you have a single point where localStorage is mutated.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But hey, if this is too much, merge it as this. It's much better than it was before. Please don't feel pressured by this. 😎
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I like your suggestion a lot. I will try to implement it :)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I am not, nice to have someone to read the code. I was starting to feeling lonely ;) Thanks a lot for the comments :) |
||
| console.log(localStorage.getItem(localStorageKey), 'token'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Especially the token shouldn't be exposed in the console for an inquisitive eyes :D |
||
| axios.defaults.headers.common['Authorization'] = | ||
| 'Bearer ' + localStorage.getItem(localStorageKey); | ||
|
|
||
| console.log('going to local storage '); | ||
| } else { | ||
| navigate('/login'); | ||
|
|
||
| console.log('redirecting'); | ||
| } | ||
| }, [authentication, localStorageKey]); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import { type Authentication, type TokenAction } from './types.ts'; | ||
| import { localStorageKey } from '../constants.ts'; | ||
|
|
||
| export type AuthenticationReducer = ( | ||
| token: Authentication, | ||
|
|
@@ -12,8 +13,10 @@ export const authenticationReducer: AuthenticationReducer = ( | |
| switch (action.type) { | ||
| case 'set': | ||
| return { token: action.token }; | ||
| case 'clear': | ||
| return { token: "" }; | ||
| case 'clear': { | ||
| localStorage.setItem(localStorageKey, ''); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not to remove the item from the storage entirely? |
||
| return { token: '' }; | ||
| } | ||
| default: | ||
| // eslint-disable-next-line @typescript-eslint/restrict-template-expressions | ||
| throw new Error(`Invalid action type ${action.type}`); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import React, { useState } from 'react'; | ||
| import React, { useEffect, useState } from 'react'; | ||
| import { useNavigate } from 'react-router-dom'; | ||
| import { Heading } from '../components/atoms/Heading/Heading.ts'; | ||
| import MainBox from '../components/atoms/Sections/MainBox.ts'; | ||
|
|
@@ -12,7 +12,7 @@ import { type User } from '../api/Authentication/userTypes.ts'; | |
| import Button from '../components/atoms/Buttons/Button.ts'; | ||
| import useAuthenticateUser from '../api/Authentication/authenticateUser.ts'; | ||
| import { useTokenDispatch } from '../providers/AuthProvider.tsx'; | ||
| import { setToken } from '../providers/authenticationActions.ts'; | ||
| import { clearToken, setToken } from '../providers/authenticationActions.ts'; | ||
|
|
||
| const Login = () => { | ||
| const [formData, setFormData] = useState<User>({ | ||
|
|
@@ -25,9 +25,13 @@ const Login = () => { | |
| const { trigger, isMutating, error } = useAuthenticateUser(); | ||
| const navigate = useNavigate(); | ||
|
|
||
| const handleSubmit = async ( | ||
| event: React.MouseEvent<HTMLButtonElement, MouseEvent> | ||
| ) => { | ||
| useEffect(() => { | ||
| clearToken(dispatch); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we would like to logout an user whenever he accesses the Login page. This method might be called when users clicks button like "logout". The better approach is to redirect the authenticated user to the app, if he reaches the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is temporary - its here, because we don't have the refresh token functionality and we never clear the token :)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add a todo to make it more clear |
||
|
|
||
| console.log(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 |
||
| }, []); | ||
|
|
||
| const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | ||
| event.preventDefault(); | ||
| const response = await trigger({ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think all the authentication process should be moved out of the
Can we move it to the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, that would be more clean |
||
| username: formData.userName, | ||
|
|
@@ -42,35 +46,29 @@ const Login = () => { | |
| <MainBox> | ||
| <StyledArticle> | ||
| <Heading>Zaloguj się</Heading> | ||
| <StyledForm onSubmit={() => handleSubmit}> | ||
| <StyledForm onSubmit={handleSubmit}> | ||
| <StyledLabel htmlFor="userName">Nazwa użytkownika:</StyledLabel> | ||
| <StyledInput | ||
| type="text" | ||
| name="userName" | ||
| id="userName" | ||
| value={formData.userName} | ||
| onChange={(event) => | ||
| setFormData({ ...formData, userName: event.target.value }) | ||
| } | ||
| required | ||
| /> | ||
| <StyledLabel htmlFor="password">Hasło:</StyledLabel> | ||
| <StyledInput | ||
| type="text" | ||
| type="password" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love this change! |
||
| name="password" | ||
| id="password" | ||
| value={formData.password} | ||
| onChange={(event) => | ||
| setFormData({ ...formData, password: event.target.value }) | ||
| } | ||
| required | ||
| /> | ||
| {error && <div>Błąd logowania. Spróbuj ponownie.</div>} | ||
| <Button | ||
| type="button" | ||
| disabled={isMutating} | ||
| onClick={(event) => handleSubmit(event)} | ||
| > | ||
| <Button type="submit" disabled={isMutating}> | ||
| Zaloguj się | ||
| </Button> | ||
| </StyledForm> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.