Skip to content

Commit

Permalink
finalize auth process
Browse files Browse the repository at this point in the history
add flow for loading auth token
add token to api auth header on app startup
add AppStateRedux to track hydration state
simplify ejs conditions
  • Loading branch information
ruddell committed Mar 18, 2017
1 parent 94b6015 commit e78b368
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 18 deletions.
2 changes: 1 addition & 1 deletion boilerplate/App/Config/ReduxPersist.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const REDUX_PERSIST = {
reducerVersion: '4',
storeConfig: {
storage: AsyncStorage,
blacklist: ['search'], // reducer keys that you do NOT want stored to persistence here
blacklist: ['appState', 'search'], // reducer keys that you do NOT want stored to persistence here
// whitelist: [], Optionally, just specify the keys you DO want stored to
// persistence. An empty array means 'don't store any reducers' -> infinitered/ignite#409
transforms: [immutablePersistenceTransform]
Expand Down
18 changes: 16 additions & 2 deletions boilerplate/App/Containers/RootContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { View, StatusBar } from 'react-native'
import NavigationRouter from '../Navigation/NavigationRouter'
import { connect } from 'react-redux'
import StartupActions from '../Redux/StartupRedux'
import LoginActions from '../Redux/LoginRedux'
import ReduxPersist from '../Config/ReduxPersist'

// Styles
Expand All @@ -17,6 +18,12 @@ class RootContainer extends Component {
}
}

componentWillReceiveProps (newProps) {
if (newProps.rehydrationComplete) {
this.props.loadLogin()
}
}

render () {
return (
<View style={styles.applicationView}>
Expand All @@ -27,9 +34,16 @@ class RootContainer extends Component {
}
}

const mapStateToProps = (state) => {
return {
rehydrationComplete: state.appState.rehydrationComplete
}
}

// wraps dispatch to create nicer functions to call within our component
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup())
startup: () => dispatch(StartupActions.startup()),
loadLogin: () => dispatch(LoginActions.loginLoad())
})

export default connect(null, mapDispatchToProps)(RootContainer)
export default connect(mapStateToProps, mapDispatchToProps)(RootContainer)
29 changes: 29 additions & 0 deletions boilerplate/App/Redux/AppStateRedux.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
setRehydrationComplete: null
})

export const AppStateTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
rehydrationComplete: false
})

/* ------------- Reducers ------------- */

// rehydration is complete
export const setRehydrationComplete = (state: Object) =>
state.merge({ rehydrationComplete: true })

/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {
[Types.SET_REHYDRATION_COMPLETE]: setRehydrationComplete
})
21 changes: 13 additions & 8 deletions boilerplate/App/Redux/LoginRedux.js.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const { Types, Creators } = createActions({
loginSuccess: ['id_token'],
loginFailure: ['error'],
logoutRequest: null,
logoutSuccess: null
logoutSuccess: null,
loginLoad: [],
loginLoadSuccess: []
})

export const LoginTypes = Types
Expand All @@ -18,7 +20,8 @@ export default Creators
export const INITIAL_STATE = Immutable({
id_token: null,
error: null,
fetching: false
fetching: false,
loading: false
})

/* ------------- Reducers ------------- */
Expand All @@ -28,12 +31,7 @@ export const request = (state) => state.merge({ fetching: true })

// we've successfully logged in
export const success = (state, data) => {
<%_ if (props.authType === 'oauth2' || props.authType === 'uaa') { _%>
return state.merge({ fetching: false, error: null, id_token: data.id_token })
<%_ } else if (props.authType === 'jwt') { _%>
const { id_token } = data.id_token
return state.merge({ fetching: false, error: null, id_token })
<%_ } _%>
}
// we've had a problem logging in
export const failure = (state, { error }) => state.merge({ fetching: false, error })
Expand All @@ -44,14 +42,21 @@ export const logoutRequest = state => state
// we've logged out
export const logoutSuccess = state => INITIAL_STATE

// we're attempting to load token from startup sagas
export const load = (state) => state.merge({ loading: true })

export const loadSuccess = (state) => state.merge({ loading: false })

/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {
[Types.LOGIN_REQUEST]: request,
[Types.LOGIN_SUCCESS]: success,
[Types.LOGIN_FAILURE]: failure,
[Types.LOGOUT_REQUEST]: logoutRequest,
[Types.LOGOUT_SUCCESS]: logoutSuccess
[Types.LOGOUT_SUCCESS]: logoutSuccess,
[Types.LOGIN_LOAD]: load,
[Types.LOGIN_LOAD_SUCCESS]: loadSuccess
})

/* ------------- Selectors ------------- */
Expand Down
1 change: 1 addition & 0 deletions boilerplate/App/Redux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import rootSaga from '../Sagas/'
export default () => {
/* ------------- Assemble The Reducers ------------- */
const rootReducer = combineReducers({
appState: require('./AppStateRedux').reducer,
github: require('./GithubRedux').reducer,
account: require('./AccountRedux').reducer,
login: require('./LoginRedux').reducer,
Expand Down
21 changes: 15 additions & 6 deletions boilerplate/App/Sagas/LoginSagas.js.ejs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { call, put } from 'redux-saga/effects'
import { call, put, select } from 'redux-saga/effects'
import LoginActions from '../Redux/LoginRedux'
import AccountActions from '../Redux/AccountRedux'

export const selectAuthToken = (state) => state.login.id_token

// attempts to login
export function * login (api, { username, password }) {

Expand All @@ -22,11 +24,7 @@ export function * login (api, { username, password }) {
// success?
if (response.ok) {
console.tron.log("Login - OK")
<%_ if (props.authType === 'oauth2' || props.authType === 'uaa') { _%>
yield call(api.setAuthToken, response.data.id_token.access_token)
<%_ } else if (props.authType === 'jwt') { _%>
yield call(api.setAuthToken, response.data.id_token)
<%_ } _%>
yield call(api.setAuthToken, response.data.id_token<%_ if (props.authType === 'oauth2' || props.authType === 'uaa') { _%>.access_token<%_ } %>)
yield put(LoginActions.loginSuccess(response.data))
yield put(AccountActions.accountRequest())
} else {
Expand All @@ -46,3 +44,14 @@ export function * logout (api) {
yield put(AccountActions.logout())
yield put(LoginActions.logoutSuccess())
}

// loads the login
export function * loginLoad (api) {
const authToken = yield select(selectAuthToken)
// only set the token if we have it
if (authToken !== null) {
console.tron.log(authToken)
yield call(api.setAuthToken, authToken<%_ if (props.authType === 'oauth2' || props.authType === 'uaa') { _%>.access_token<%_ } %>)
}
yield put(LoginActions.loginLoadSuccess())
}
2 changes: 2 additions & 0 deletions boilerplate/App/Sagas/StartupSagas.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { put, select } from 'redux-saga/effects'
import AppStateActions from '../Redux/AppStateRedux'
import GithubActions from '../Redux/GithubRedux'
import { is } from 'ramda'

Expand Down Expand Up @@ -37,4 +38,5 @@ export function * startup (action) {
if (!is(String, avatar)) {
yield put(GithubActions.userRequest('GantMan'))
}
yield put(AppStateActions.setRehydrationComplete())
}
3 changes: 2 additions & 1 deletion boilerplate/App/Sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { AccountTypes } from '../Redux/AccountRedux'
/* ------------- Sagas ------------- */

import { startup } from './StartupSagas'
import { login, logout } from './LoginSagas'
import { login, logout, loginLoad } from './LoginSagas'
import { register } from './RegisterSagas'
import { forgotPasswordRequest } from './ForgotPasswordSagas'
import { getUserAvatar } from './GithubSagas'
Expand All @@ -41,6 +41,7 @@ export default function * root () {
takeLatest(OpenScreenTypes.OPEN_SCREEN, openScreen),

// JHipster accounts
takeLatest(LoginTypes.LOGIN_LOAD, loginLoad, jhipsterApi),
takeLatest(LoginTypes.LOGIN_REQUEST, login, jhipsterApi),
takeLatest(LoginTypes.LOGOUT_REQUEST, logout, jhipsterApi),
takeLatest(RegisterTypes.REGISTER_REQUEST, register, jhipsterApi),
Expand Down

0 comments on commit e78b368

Please sign in to comment.