Lazar Kostic 3 лет назад
Родитель
Сommit
55522c5e32

+ 1
- 0
package.json Просмотреть файл

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

+ 3
- 3
src/AppRoutes.js Просмотреть файл

NOT_FOUND_PAGE, NOT_FOUND_PAGE,
ERROR_PAGE, ERROR_PAGE,
BASE_PAGE, BASE_PAGE,
GOOGLE_AUTH_CALLBACK_PAGE,
AUTH_CALLBACK_PAGE,
REGISTER_PAGE, REGISTER_PAGE,
} from "./constants/pages"; } from "./constants/pages";


import ErrorPage from "./pages/ErrorPages/ErrorPage"; import ErrorPage from "./pages/ErrorPages/ErrorPage";
import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI";
import PrivateRoute from "./components/Router/PrivateRoute"; import PrivateRoute from "./components/Router/PrivateRoute";
import GoogleAuthCallback from "./pages/GoogleAuthCallback/GoogleAuthCallback";
import AuthCallback from "./pages/AuthCallback/AuthCallback";
import RegisterPage from "./pages/RegisterPage/RegisterPageMUI"; import RegisterPage from "./pages/RegisterPage/RegisterPageMUI";


const AppRoutes = () => ( const AppRoutes = () => (
<Route exact path={BASE_PAGE} component={LoginPage} /> <Route exact path={BASE_PAGE} component={LoginPage} />
<Route exact path={LOGIN_PAGE} component={LoginPage} /> <Route exact path={LOGIN_PAGE} component={LoginPage} />
<Route exact path={REGISTER_PAGE} component={RegisterPage} /> <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={NOT_FOUND_PAGE} component={NotFoundPage} />
<Route path={ERROR_PAGE} component={ErrorPage} /> <Route path={ERROR_PAGE} component={ErrorPage} />
<Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />

+ 1
- 1
src/constants/pages.js Просмотреть файл

export const HOME_PAGE = '/home'; export const HOME_PAGE = '/home';
export const ERROR_PAGE = '/error-page'; export const ERROR_PAGE = '/error-page';
export const NOT_FOUND_PAGE = '/not-found'; 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 Просмотреть файл

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 Просмотреть файл

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 Просмотреть файл

authentications: { authentications: {
getUsernames: 'authenticate/usernames', getUsernames: 'authenticate/usernames',
login: 'api/auth/local', login: 'api/auth/local',
authProvider: 'api/auth/{provider}/callback?{search}',
register: 'api/auth/local/register', register: 'api/auth/local/register',
getUserSecurityQuestion: 'users/username/securityquestion', getUserSecurityQuestion: 'users/username/securityquestion',
confirmSecurityQuestion: 'authenticate/confirm', confirmSecurityQuestion: 'authenticate/confirm',

+ 3
- 3
src/request/index.js Просмотреть файл

import axios from "axios"; import axios from "axios";
// import queryString from 'qs';
import queryString from "qs";


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


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

+ 9
- 1
src/request/loginRequest.js Просмотреть файл

import { getRequest, postRequest } from "./index";
import { getRequest, postRequest, replaceInUrl } from "./index";
import apiEndpoints from "./apiEndpoints"; import apiEndpoints from "./apiEndpoints";


export const getUsernames = (emailorusername) => export const getUsernames = (emailorusername) =>
export const attemptLogin = (payload) => export const attemptLogin = (payload) =>
postRequest(apiEndpoints.authentications.login, payload); postRequest(apiEndpoints.authentications.login, payload);


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

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



+ 6
- 0
src/store/actions/authProvider/authProviderActionConstants.js Просмотреть файл

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 Просмотреть файл

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 Просмотреть файл

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 Просмотреть файл

import userReducer from './user/userReducer'; import userReducer from './user/userReducer';
import randomDataReducer from './randomData/randomDataReducer'; import randomDataReducer from './randomData/randomDataReducer';
import registerReducer from './register/registerReducer' import registerReducer from './register/registerReducer'
import auhtProviderReducer from './authProvider/auhtProviderReducer';



export default combineReducers({ export default combineReducers({
login: loginReducer, login: loginReducer,
loading:loadingReducer, loading:loadingReducer,
randomData: randomDataReducer, randomData: randomDataReducer,
register: registerReducer, register: registerReducer,
authProvider: auhtProviderReducer
}); });

+ 48
- 0
src/store/saga/authProviderSaga.js Просмотреть файл

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 Просмотреть файл

import { all } from "redux-saga/effects"; import { all } from "redux-saga/effects";
import loginSaga from "./loginSaga"; import loginSaga from "./loginSaga";
import registerSaga from "./registerSaga"; import registerSaga from "./registerSaga";
import authProviderSaga from "./authProviderSaga";


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

+ 9
- 0
src/store/selectors/authProviderSelectors.js Просмотреть файл

import { createSelector } from 'reselect';

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


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

+ 7
- 0
yarn.lock Просмотреть файл

resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 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: query-string@^4.1.0:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"

Загрузка…
Отмена
Сохранить