feature/google_login en FE_dev hace 3 años
| @@ -25,6 +25,7 @@ | |||
| "i18next": "^20.3.1", | |||
| "json-server": "^0.17.0", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "jwt-decode": "^3.1.2", | |||
| "lodash": "^4.17.21", | |||
| "lodash.isempty": "^4.4.0", | |||
| "owasp-password-strength-test": "^1.3.0", | |||
| @@ -14613,6 +14614,11 @@ | |||
| "safe-buffer": "^5.0.1" | |||
| } | |||
| }, | |||
| "node_modules/jwt-decode": { | |||
| "version": "3.1.2", | |||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| }, | |||
| "node_modules/keyv": { | |||
| "version": "3.1.0", | |||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | |||
| @@ -35559,6 +35565,11 @@ | |||
| "safe-buffer": "^5.0.1" | |||
| } | |||
| }, | |||
| "jwt-decode": { | |||
| "version": "3.1.2", | |||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| }, | |||
| "keyv": { | |||
| "version": "3.1.0", | |||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | |||
| @@ -20,6 +20,7 @@ | |||
| "i18next": "^20.3.1", | |||
| "json-server": "^0.17.0", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "jwt-decode": "^3.1.2", | |||
| "lodash": "^4.17.21", | |||
| "lodash.isempty": "^4.4.0", | |||
| "owasp-password-strength-test": "^1.3.0", | |||
| @@ -31,6 +31,7 @@ | |||
| Learn how to configure a non-root public URL by running `npm run build`. | |||
| --> | |||
| <title>React App</title> | |||
| <script src="https://accounts.google.com/gsi/client" async defer></script> | |||
| </head> | |||
| <body> | |||
| <noscript>You need to enable JavaScript to run this app.</noscript> | |||
| @@ -47,4 +47,18 @@ input[type='search']::-webkit-search-results-decoration { | |||
| ul { | |||
| list-style: none; | |||
| padding: 0; | |||
| } | |||
| .S9gUrf-YoZ4jf { | |||
| @include flex-center; | |||
| width: 100% !important; | |||
| overflow: hidden; | |||
| padding: 0 !important; | |||
| margin: 0 !important; | |||
| } | |||
| .S9gUrf-YoZ4jf > * { | |||
| margin: auto; | |||
| padding: 0 !important; | |||
| margin: 0 !important; | |||
| } | |||
| @@ -8,10 +8,12 @@ import * as Yup from "yup"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import HrLogo from "../../assets/images/hrcenter.png"; | |||
| import DiligLogo from "../../assets/images/logo_horizontal_black.png"; | |||
| import jwt_decode from "jwt-decode"; | |||
| import googleLogo from "../../assets/images/google1.png"; | |||
| import { | |||
| clearLoginErrors, | |||
| fetchUser, | |||
| fetchGoogleUser, | |||
| } from "../../store/actions/login/loginActions"; | |||
| import { selectLoginError } from "../../store/selectors/loginSelectors"; | |||
| import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages"; | |||
| @@ -37,6 +39,7 @@ const LoginPage = ({ history }) => { | |||
| const error = useSelector(selectLoginError); | |||
| const [showPassword, setShowPassword] = useState(false); | |||
| const [isInit, setIsInit] = useState(true); | |||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | |||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | |||
| @@ -51,6 +54,20 @@ const LoginPage = ({ history }) => { | |||
| redirectClient(); | |||
| }, [history]); | |||
| const handleCallbackResponse = (response) => { | |||
| const userObject = jwt_decode(response.credential); | |||
| const user = userObject; | |||
| const token = response.credential; | |||
| dispatch(clearLoginErrors()); | |||
| dispatch( | |||
| fetchGoogleUser({ | |||
| user, | |||
| token, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| }; | |||
| const isLoading = useSelector( | |||
| selectIsLoadingByActionType(LOGIN_USER_LOADING) | |||
| ); | |||
| @@ -65,7 +82,7 @@ const LoginPage = ({ history }) => { | |||
| }; | |||
| const handleSubmit = (values) => { | |||
| const { username,password } = values; | |||
| const { username, password } = values; | |||
| dispatch(clearLoginErrors()); | |||
| dispatch( | |||
| fetchUser({ | |||
| @@ -76,6 +93,38 @@ const LoginPage = ({ history }) => { | |||
| ); | |||
| }; | |||
| useEffect(() => { | |||
| if (isInit) { | |||
| setIsInit(false); | |||
| return; | |||
| } | |||
| google.accounts.id.initialize({ | |||
| client_id: | |||
| "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com", | |||
| callback: handleCallbackResponse, | |||
| }); | |||
| google.accounts.id.renderButton(document.getElementById("signInDiv"), { | |||
| theme: "outline", | |||
| size: "large", | |||
| width: "250", | |||
| }); | |||
| }, [isInit]); | |||
| // const handleGoogleSubmit = (values) => { | |||
| // /* global google */ | |||
| // google.accounts.id.initialize({ | |||
| // client_id: | |||
| // "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com", | |||
| // callback: handleCallbackResponse, | |||
| // }); | |||
| // google.accounts.id.renderButton(document.getElementById("signInDiv"), { | |||
| // theme: "outline", | |||
| // size: "large", | |||
| // }); | |||
| // }; | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| username: "", | |||
| @@ -183,15 +232,19 @@ const LoginPage = ({ history }) => { | |||
| <div className="hr-mid">{t("common.or")}</div> | |||
| <div className="hr hr-e"></div> | |||
| </div> | |||
| <Button | |||
| className="c-btn c-btn--gray flex-center" | |||
| sx={{ width: "100%", mt: 2 }} | |||
| > | |||
| <img src={googleLogo} style={{ marginRight: "15px" }} /> | |||
| <Typography sx={{ m: 0, p: 0 }} variant="buttonText"> | |||
| {t("login.signInWithGoogle")} | |||
| </Typography> | |||
| </Button> | |||
| <div> | |||
| {/* <Button | |||
| className="c-btn c-btn--gray flex-center" | |||
| sx={{ width: "100%", mt: 2 }} | |||
| onClick={handleGoogleSubmit} | |||
| > | |||
| <img src={googleLogo} style={{ marginRight: "15px" }} /> | |||
| <Typography sx={{ m: 0, p: 0 }} variant="buttonText"> | |||
| {t("login.signInWithGoogle")} | |||
| </Typography> | |||
| </Button> */} | |||
| <div id="signInDiv"></div> | |||
| </div> | |||
| <div className="flex-center"> | |||
| <img src={DiligLogo} style={{ margin: "70px auto 0px auto" }} /> | |||
| </div> | |||
| @@ -1,6 +1,9 @@ | |||
| const base = "http://localhost:26081/v1"; | |||
| export default { | |||
| authentications: { | |||
| login: 'http://localhost:26081/v1/users/authenticate', | |||
| refreshToken:'http://localhost:26081/v1/users/refresh' | |||
| login: base + "/users/authenticate", | |||
| googleLogin: base + "/users/authenticateGoogle", | |||
| refreshToken: base + "/users/refresh", | |||
| }, | |||
| }; | |||
| @@ -9,6 +9,9 @@ export const getUsernames = (emailorusername) => | |||
| export const attemptLogin = (payload) => | |||
| postRequest(apiEndpoints.authentications.login, payload); | |||
| export const attemptGoogleLogin = (payload) => | |||
| postRequest(apiEndpoints.authentications.googleLogin, payload); | |||
| export const updateSecurityAnswer = (payload) => | |||
| postRequest(apiEndpoints.authentications.confirmSecurityQuestion, payload); | |||
| @@ -17,6 +17,15 @@ export const CLEAR_LOGIN_USER_ERROR = createClearType( | |||
| ); | |||
| export const LOGIN_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | |||
| const LOGIN_GOOGLE_USER_SCOPE = 'LOGIN_GOOGLE_USER'; | |||
| export const LOGIN_GOOGLE_USER_FETCH = createFetchType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const LOGIN_GOOGLE_USER_SUCCESS = createSuccessType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const LOGIN_GOOGLE_USER_ERROR = createErrorType(LOGIN_GOOGLE_USER_SCOPE); | |||
| export const CLEAR_LOGIN_GOOGLE_USER_ERROR = createClearType( | |||
| `${LOGIN_GOOGLE_USER_SCOPE}_ERROR`, | |||
| ); | |||
| export const LOGIN_GOOGLE_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | |||
| export const UPDATE_USER_JWT_TOKEN = 'UPDATE_USER_JWT_TOKEN'; | |||
| export const RESET_LOGIN_STATE = 'RESET_LOGIN_STATE'; | |||
| @@ -4,6 +4,9 @@ import { | |||
| LOGIN_USER_ERROR, | |||
| LOGIN_USER_FETCH, | |||
| LOGIN_USER_SUCCESS, | |||
| LOGIN_GOOGLE_USER_ERROR, | |||
| LOGIN_GOOGLE_USER_FETCH, | |||
| LOGIN_GOOGLE_USER_SUCCESS, | |||
| LOGOUT_USER, | |||
| RESET_LOGIN_STATE, | |||
| UPDATE_USER_JWT_TOKEN, | |||
| @@ -19,16 +22,31 @@ export const fetchUser = (payload) => ({ | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUser = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_FETCH, | |||
| payload, | |||
| }); | |||
| export const fetchUserSuccess = (payload) => ({ | |||
| type: LOGIN_USER_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUserSuccess = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const fetchUserError = (payload) => ({ | |||
| type: LOGIN_USER_ERROR, | |||
| payload, | |||
| }); | |||
| export const fetchGoogleUserError = (payload) => ({ | |||
| type: LOGIN_GOOGLE_USER_ERROR, | |||
| payload, | |||
| }); | |||
| export const updateUserToken = (payload) => ({ | |||
| type: UPDATE_USER_JWT_TOKEN, | |||
| payload | |||
| @@ -3,12 +3,14 @@ import jwt from 'jsonwebtoken'; | |||
| import history from '../utils/history'; | |||
| import { | |||
| AUTHENTICATE_USER, | |||
| LOGIN_GOOGLE_USER_FETCH, | |||
| LOGIN_USER_FETCH, | |||
| LOGOUT_USER, | |||
| REFRESH_TOKEN, | |||
| GENERATE_TOKEN, | |||
| } from '../actions/login/loginActionConstants'; | |||
| import { | |||
| attemptGoogleLogin, | |||
| attemptLogin, | |||
| logoutUserRequest, | |||
| refreshTokenRequest, | |||
| @@ -67,6 +69,31 @@ function* fetchUser({ payload }) { | |||
| } | |||
| } | |||
| } | |||
| function* fetchGoogleUser({ payload }) { | |||
| try { | |||
| const { data } = yield call(attemptGoogleLogin, payload); | |||
| if (data.token) { | |||
| // const user = jwt.decode(data.token); | |||
| yield call(authScopeSetHelper, JWT_TOKEN, data.token); | |||
| yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken); | |||
| yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken); | |||
| yield call(addHeaderToken, data.token); | |||
| yield put(setUser(data)); | |||
| } | |||
| yield put(fetchUserSuccess(data)); | |||
| if (payload.handleApiResponseSuccess) { | |||
| yield call(payload.handleApiResponseSuccess); | |||
| } | |||
| } catch (e) { | |||
| if (e.response && e.response.data) { | |||
| if (payload.handleApiResponseFailed) { | |||
| yield call(payload.handleApiResponseFailed); | |||
| } | |||
| const errorMessage = yield call(rejectErrorCodeHelper, e); | |||
| yield put(fetchUserError(errorMessage)); | |||
| } | |||
| } | |||
| } | |||
| function* authenticateUser() { | |||
| try { | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| @@ -165,6 +192,7 @@ export function* generateToken({ payload }) { | |||
| export default function* loginSaga() { | |||
| yield all([ | |||
| takeLatest(LOGIN_USER_FETCH, fetchUser), | |||
| takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser), | |||
| takeLatest(AUTHENTICATE_USER, authenticateUser), | |||
| takeLatest(LOGOUT_USER, logoutUser), | |||
| takeLatest(REFRESH_TOKEN, refreshToken), | |||
| @@ -7845,6 +7845,11 @@ | |||
| "jwa" "^1.4.1" | |||
| "safe-buffer" "^5.0.1" | |||
| "jwt-decode@^3.1.2": | |||
| "integrity" "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||
| "resolved" "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" | |||
| "version" "3.1.2" | |||
| "keyv@^3.0.0": | |||
| "integrity" "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==" | |||
| "resolved" "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" | |||