Przeglądaj źródła

Auth provider

master
Lazar Kostic 3 lat temu
rodzic
commit
55522c5e32

+ 1
- 0
package.json Wyświetl plik

@@ -24,6 +24,7 @@
"lodash": "^4.17.21",
"lodash.isempty": "^4.4.0",
"owasp-password-strength-test": "^1.3.0",
"qs": "^6.11.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet-async": "^1.0.9",

+ 3
- 3
src/AppRoutes.js Wyświetl plik

@@ -8,7 +8,7 @@ import {
NOT_FOUND_PAGE,
ERROR_PAGE,
BASE_PAGE,
GOOGLE_AUTH_CALLBACK_PAGE,
AUTH_CALLBACK_PAGE,
REGISTER_PAGE,
} from "./constants/pages";

@@ -18,7 +18,7 @@ import NotFoundPage from "./pages/ErrorPages/NotFoundPage";
import ErrorPage from "./pages/ErrorPages/ErrorPage";
import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI";
import PrivateRoute from "./components/Router/PrivateRoute";
import GoogleAuthCallback from "./pages/GoogleAuthCallback/GoogleAuthCallback";
import AuthCallback from "./pages/AuthCallback/AuthCallback";
import RegisterPage from "./pages/RegisterPage/RegisterPageMUI";

const AppRoutes = () => (
@@ -26,7 +26,7 @@ const AppRoutes = () => (
<Route exact path={BASE_PAGE} component={LoginPage} />
<Route exact path={LOGIN_PAGE} component={LoginPage} />
<Route exact path={REGISTER_PAGE} component={RegisterPage} />
<Route path={GOOGLE_AUTH_CALLBACK_PAGE} component={GoogleAuthCallback} />
<Route path={AUTH_CALLBACK_PAGE} component={AuthCallback} />
<Route path={NOT_FOUND_PAGE} component={NotFoundPage} />
<Route path={ERROR_PAGE} component={ErrorPage} />
<Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />

+ 1
- 1
src/constants/pages.js Wyświetl plik

@@ -5,4 +5,4 @@ export const FORGOT_PASSWORD_PAGE = '/forgot-password';
export const HOME_PAGE = '/home';
export const ERROR_PAGE = '/error-page';
export const NOT_FOUND_PAGE = '/not-found';
export const GOOGLE_AUTH_CALLBACK_PAGE = '/api/auth/google/callback'
export const AUTH_CALLBACK_PAGE = '/api/auth/:provider/callback'

+ 54
- 0
src/pages/AuthCallback/AuthCallback.js Wyświetl plik

@@ -0,0 +1,54 @@
import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { HOME_PAGE } from "../../constants/pages";
import PropTypes from "prop-types";
import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { fetchAuthProvider } from "../../store/actions/authProvider/authProviderActions";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { AUTH_PROVIDER_SCOPE } from "../../store/actions/authProvider/authProviderActionConstants";
import Backdrop from '../../components/MUI/BackdropComponent';

function AuthCallback({ history }) {
const dispatch = useDispatch();
const { provider } = useParams();
const location = useLocation();

const handleApiResponseSuccess = () => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
};

const isLoading = useSelector(selectIsLoadingByActionType(AUTH_PROVIDER_SCOPE));

useEffect(() => {
if (!location) {
return;
}
const { search } = location;

dispatch(fetchAuthProvider({ provider, search, handleApiResponseSuccess }));
}, [location]);

return (
<div>
{isLoading && <Backdrop position="absolute" isLoading={isLoading} />}
</div>
);
}

AuthCallback.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
};

export default AuthCallback;

+ 0
- 60
src/pages/GoogleAuthCallback/GoogleAuthCallback.js Wyświetl plik

@@ -1,60 +0,0 @@
import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { authScopeSetHelper } from "../../util/helpers/authScopeHelpers";
import { addHeaderToken } from "../../request";
import { HOME_PAGE } from "../../constants/pages";
import { JWT_REFRESH_TOKEN, JWT_TOKEN } from "../../constants/localStorage";
import { setUser } from "../../store/actions/user/userActions";
import PropTypes from "prop-types";
import axios from "axios";

function GoogleAuthCallback({ history }) {
const location = useLocation();

const handleApiResponseSuccess = () => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
};

useEffect(() => {
if (!location) {
return;
}
const { search } = location;
axios({
method: "GET",
url: `http://localhost:1337/api/auth/google/callback?${search}`,
}).then((res) => {
if (res.data?.jwt) {
const user = res.data?.user;
authScopeSetHelper(JWT_TOKEN, res.data.jwt);
authScopeSetHelper(JWT_REFRESH_TOKEN, res.data.refreshToken);
addHeaderToken(res.data?.jwt);
setUser(user);
handleApiResponseSuccess();
}
});
}, [location]);

return (
<div>
<></>
</div>
);
}

GoogleAuthCallback.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
};

export default GoogleAuthCallback;

+ 1
- 0
src/request/apiEndpoints.js Wyświetl plik

@@ -18,6 +18,7 @@ export default {
authentications: {
getUsernames: 'authenticate/usernames',
login: 'api/auth/local',
authProvider: 'api/auth/{provider}/callback?{search}',
register: 'api/auth/local/register',
getUserSecurityQuestion: 'users/username/securityquestion',
confirmSecurityQuestion: 'authenticate/confirm',

+ 3
- 3
src/request/index.js Wyświetl plik

@@ -1,5 +1,5 @@
import axios from "axios";
// import queryString from 'qs';
import queryString from "qs";

const request = axios.create({
baseURL: "http://localhost:1337/",
@@ -7,8 +7,8 @@ const request = axios.create({
"Content-Type": "application/json",
},
//withCredentials: true,
// paramsSerializer: (params) =>
// queryString.stringify(params, { arrayFormat: 'comma' }),
paramsSerializer: (params) =>
queryString.stringify(params, { arrayFormat: "comma" }),
});

export const getRequest = (url, params = null, options = null) =>

+ 9
- 1
src/request/loginRequest.js Wyświetl plik

@@ -1,4 +1,4 @@
import { getRequest, postRequest } from "./index";
import { getRequest, postRequest, replaceInUrl } from "./index";
import apiEndpoints from "./apiEndpoints";

export const getUsernames = (emailorusername) =>
@@ -9,6 +9,14 @@ export const getUsernames = (emailorusername) =>
export const attemptLogin = (payload) =>
postRequest(apiEndpoints.authentications.login, payload);

export const attemptAuthProvider = (provider, search) =>
getRequest(
replaceInUrl(apiEndpoints.authentications.authProvider, {
provider,
search,
})
);

export const attemptRegister = (payload) =>
postRequest(apiEndpoints.authentications.register, payload);


+ 6
- 0
src/store/actions/authProvider/authProviderActionConstants.js Wyświetl plik

@@ -0,0 +1,6 @@
import { createErrorType, createFetchType, createSuccessType } from "../actionHelpers";

export const AUTH_PROVIDER_SCOPE = 'AUTH_PROVIDER';
export const AUTH_PROVIDER_FETCH = createFetchType(AUTH_PROVIDER_SCOPE);
export const AUTH_PROVIDER_SUCCESS = createSuccessType(AUTH_PROVIDER_SCOPE);
export const AUTH_PROVIDER_ERROR = createErrorType(AUTH_PROVIDER_SCOPE);

+ 20
- 0
src/store/actions/authProvider/authProviderActions.js Wyświetl plik

@@ -0,0 +1,20 @@
import {
AUTH_PROVIDER_ERROR,
AUTH_PROVIDER_FETCH,
AUTH_PROVIDER_SUCCESS,
} from "./authProviderActionConstants";

export const fetchAuthProvider = (payload) => ({
type: AUTH_PROVIDER_FETCH,
payload,
});

export const fetchAuthProviderSuccess = (payload) => ({
type: AUTH_PROVIDER_SUCCESS,
payload,
});

export const fetchAuthProviderError = (payload) => ({
type: AUTH_PROVIDER_ERROR,
payload,
});

+ 37
- 0
src/store/reducers/authProvider/auhtProviderReducer.js Wyświetl plik

@@ -0,0 +1,37 @@
import createReducer from "../../utils/createReducer";

import {
AUTH_PROVIDER_ERROR,
AUTH_PROVIDER_SUCCESS,
} from "../../actions/authProvider/authProviderActionConstants";

const initialState = {
success: "",
errorMessage: "",
};

export default createReducer(
{
[AUTH_PROVIDER_SUCCESS]: setProvider,
[AUTH_PROVIDER_ERROR]: setProviderError,
},
initialState
);

function setProvider(state, action) {
return {
...state,
successMessage: action.payload,
};
}


function setProviderError(state, action) {
return {
...state,
errorMessage: action.payload,
};
}




+ 3
- 0
src/store/reducers/index.js Wyświetl plik

@@ -4,6 +4,8 @@ import loadingReducer from './loading/loadingReducer';
import userReducer from './user/userReducer';
import randomDataReducer from './randomData/randomDataReducer';
import registerReducer from './register/registerReducer'
import auhtProviderReducer from './authProvider/auhtProviderReducer';


export default combineReducers({
login: loginReducer,
@@ -11,4 +13,5 @@ export default combineReducers({
loading:loadingReducer,
randomData: randomDataReducer,
register: registerReducer,
authProvider: auhtProviderReducer
});

+ 48
- 0
src/store/saga/authProviderSaga.js Wyświetl plik

@@ -0,0 +1,48 @@
import { all, call, put, takeLatest } from "@redux-saga/core/effects";
import { attemptAuthProvider } from "../../request/loginRequest";
import {
fetchUserError,
fetchUserSuccess,
} from "../actions/login/loginActions";
import { setUser } from "../actions/user/userActions";
import { addHeaderToken } from "../../request";
import {
JWT_REFRESH_TOKEN,
JWT_TOKEN,
} from "../../constants/localStorage";
import {
authScopeSetHelper,
} from "../../util/helpers/authScopeHelpers";
import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper";
import { AUTH_PROVIDER_FETCH } from "../actions/authProvider/authProviderActionConstants";
import { fetchAuthProviderError, fetchAuthProviderSuccess } from "../actions/authProvider/authProviderActions";

function* fetchAuthProvider({ payload }) {
try {
const { data } = yield call(attemptAuthProvider, payload.provider, payload.search);
if (data?.jwt) {
const user = data?.user;
yield call(authScopeSetHelper, JWT_TOKEN, data.jwt);
yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data?.refreshToken);
yield call(addHeaderToken, data?.jwt);
yield put(setUser(user));
}
yield put(fetchUserSuccess(data));
yield put (fetchAuthProviderSuccess('Success'))
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (e) {
if (e.response && e.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, e);
yield put(fetchUserError(errorMessage));
yield put(fetchAuthProviderError('Error'))
}
}
}

export default function* authProviderSaga() {
yield all([
takeLatest(AUTH_PROVIDER_FETCH, fetchAuthProvider),
]);
}

+ 2
- 1
src/store/saga/index.js Wyświetl plik

@@ -1,7 +1,8 @@
import { all } from "redux-saga/effects";
import loginSaga from "./loginSaga";
import registerSaga from "./registerSaga";
import authProviderSaga from "./authProviderSaga";

export default function* rootSaga() {
yield all([loginSaga(), registerSaga()]);
yield all([loginSaga(), registerSaga(), authProviderSaga()]);
}

+ 9
- 0
src/store/selectors/authProviderSelectors.js Wyświetl plik

@@ -0,0 +1,9 @@
import { createSelector } from 'reselect';

const authProviderSelector = (state) => state.authProvider;


export const selectLoginError = createSelector(
authProviderSelector,
(state) => state.errorMessage,
);

+ 7
- 0
yarn.lock Wyświetl plik

@@ -9964,6 +9964,13 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==

qs@^6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"

query-string@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"

Ładowanie…
Anuluj
Zapisz