Redux를 사용하여 JWT 토큰을 새로 고치는 방법
React Native Redux 앱은 인증에 JWT 토큰을 사용합니다.이러한 토큰을 필요로 하는 동작은 여러 가지가 있으며, 앱 로드 시 등에 많은 토큰이 동시에 디스패치됩니다.
예.
componentDidMount() {
dispath(loadProfile());
dispatch(loadAssets());
...
}
다.loadProfile
★★★★★★★★★★★★★★★★★」loadAssets
JWT에 대해서되며, 「 」는 「 」로 됩니다.AsyncStorage
이치노
원래 토큰 유효기간을 처리하기 위해 미들웨어를 사용하려고 했습니다.
// jwt-middleware.js
export function refreshJWTToken({ dispatch, getState }) {
return (next) => (action) => {
if (isExpired(getState().auth.token)) {
return dispatch(refreshToken())
.then(() => next(action))
.catch(e => console.log('error refreshing token', e));
}
return next(action);
};
}
이 양쪽 입니다.loadProfile
★★★★★★★★★★★★★★★★★」loadAssets
액션이 디스패치되면 토큰이 만료되기 때문입니다.토큰이 새로 고쳐질 때까지 인증이 필요한 작업을 "일시 중지"하는 것이 이상적입니다.들웨어로 할는? 는? ????
이 문제를 해결할 방법을 찾았어요.이것이 베스트 프랙티스 어프로치인지 아닌지는 잘 모르겠습니다만, 아마 개선할 수 있는 것이 있을 것입니다.
JWT를 이용하다는 먼저 .thunk
thunk
용됩니니다다
...
const createStoreWithMiddleware = applyMiddleware(jwt, thunk)(createStore);
다음으로 미들웨어 코드에서 비동기 액션 전에 토큰이 만료되었는지 확인합니다.기한이 만료된 경우 이미 토큰을 갱신하고 있는지 여부도 확인합니다.이러한 체크를 할 수 있도록 새로운 토큰에 대한 약속을 스테이트에 추가합니다.
import { refreshToken } from '../actions/auth';
export function jwt({ dispatch, getState }) {
return (next) => (action) => {
// only worry about expiring token for async actions
if (typeof action === 'function') {
if (getState().auth && getState().auth.token) {
// decode jwt so that we know if and when it expires
var tokenExpiration = jwtDecode(getState().auth.token).<your field for expiration>;
if (tokenExpiration && (moment(tokenExpiration) - moment(Date.now()) < 5000)) {
// make sure we are not already refreshing the token
if (!getState().auth.freshTokenPromise) {
return refreshToken(dispatch).then(() => next(action));
} else {
return getState().auth.freshTokenPromise.then(() => next(action));
}
}
}
}
return next(action);
};
}
은 '아까운 부분'입니다.refreshToken
될 때 약속을 스테이트에 .이 함수는 토큰이 갱신될 때 상태를 새로운 토큰에 대한 약속을 포함하도록 액션을 디스패치해야 합니다.이와 같이 토큰 인증을 동시에 사용하는 여러 비동기 액션을 디스패치하면 토큰은 한 번만 새로 고쳐집니다.
export function refreshToken(dispatch) {
var freshTokenPromise = fetchJWTToken()
.then(t => {
dispatch({
type: DONE_REFRESHING_TOKEN
});
dispatch(saveAppToken(t.token));
return t.token ? Promise.resolve(t.token) : Promise.reject({
message: 'could not refresh token'
});
})
.catch(e => {
console.log('error refreshing token', e);
dispatch({
type: DONE_REFRESHING_TOKEN
});
return Promise.reject(e);
});
dispatch({
type: REFRESHING_TOKEN,
// we want to keep track of token promise in the state so that we don't try to refresh
// the token again while refreshing is in process
freshTokenPromise
});
return freshTokenPromise;
}
난 이게 꽤 복잡하다는 걸 알아.또, 에서의 액션의 디스패치가 조금 걱정됩니다.refreshToken
행동 자체가 아닙니다.유효기간이 지난 JWT 토큰을 redux로 처리하는 다른 방법을 알려주세요.
작업이 완료될 때까지 "대기"하는 대신 저장 변수를 유지하여 토큰을 계속 가져오는지 여부를 확인할 수 있습니다.
샘플 리듀서
const initialState = {
fetching: false,
};
export function reducer(state = initialState, action) {
switch(action.type) {
case 'LOAD_FETCHING':
return {
...state,
fetching: action.fetching,
}
}
}
이제 액션 크리에이터:
export function loadThings() {
return (dispatch, getState) => {
const { auth, isLoading } = getState();
if (!isExpired(auth.token)) {
dispatch({ type: 'LOAD_FETCHING', fetching: false })
dispatch(loadProfile());
dispatch(loadAssets());
} else {
dispatch({ type: 'LOAD_FETCHING', fetching: true })
dispatch(refreshToken());
}
};
}
이것은 컴포넌트가 마운트되면 호출됩니다., 이는 " "를 합니다.fetching
및를 새로 .프로파일 또는 자산은 아직 로드하지 않습니다.
새 구성 요소:
componentDidMount() {
dispath(loadThings());
// ...
}
componentWillReceiveProps(newProps) {
const { fetching, token } = newProps; // bound from store
// assuming you have the current token stored somewhere
if (token === storedToken) {
return; // exit early
}
if (!fetching) {
loadThings()
}
}
이제 소품을 받을 때 특정 조건 하에서 물건을 적재하려고 시도합니다(매장이 바뀌면 호출됩니다).fetching
여기서) 초기 페치가 실패했을 경우, 이 에러는,refreshToken
이 작업이 완료되면 스토어에 새로운 토큰이 설정되고 컴포넌트가 갱신되어 호출됩니다.componentWillReceiveProps
. 아직 가져오지 않은 경우(이 체크가 필요한지 확실하지 않음), 로딩됩니다.
나는 간단한 포장지를 만들었다.redux-api-middleware
액션을 연기하고 액세스 토큰을 새로 고칩니다.
미들웨어.다운로드
import { isRSAA, apiMiddleware } from 'redux-api-middleware';
import { TOKEN_RECEIVED, refreshAccessToken } from './actions/auth'
import { refreshToken, isAccessTokenExpired } from './reducers'
export function createApiMiddleware() {
const postponedRSAAs = []
return ({ dispatch, getState }) => {
const rsaaMiddleware = apiMiddleware({dispatch, getState})
return (next) => (action) => {
const nextCheckPostponed = (nextAction) => {
// Run postponed actions after token refresh
if (nextAction.type === TOKEN_RECEIVED) {
next(nextAction);
postponedRSAAs.forEach((postponed) => {
rsaaMiddleware(next)(postponed)
})
} else {
next(nextAction)
}
}
if(isRSAA(action)) {
const state = getState(),
token = refreshToken(state)
if(token && isAccessTokenExpired(state)) {
postponedRSAAs.push(action)
if(postponedRSAAs.length === 1) {
return rsaaMiddleware(nextCheckPostponed)(refreshAccessToken(token))
} else {
return
}
}
return rsaaMiddleware(next)(action);
}
return next(action);
}
}
}
export default createApiMiddleware();
토큰을 상태로 유지하고 단순 도우미를 사용하여 액세스 토큰을 요청 헤더에 주입합니다.
export function withAuth(headers={}) {
return (state) => ({
...headers,
'Authorization': `Bearer ${accessToken(state)}`
})
}
그렇게redux-api-middleware
동작은 거의 변경되지 않습니다.
export const echo = (message) => ({
[RSAA]: {
endpoint: '/api/echo/',
method: 'POST',
body: JSON.stringify({message: message}),
headers: withAuth({ 'Content-Type': 'application/json' }),
types: [
ECHO_REQUEST, ECHO_SUCCESS, ECHO_FAILURE
]
}
})
JWT 리프레시 토큰 워크플로우가 동작하고 있는 것을 나타내는 프로젝트 예제를 작성했습니다.
redux는 토큰 리프레시의 원자성을 강제하기 위한 적절한 툴이 아니라고 생각합니다.
대신 어디서든 호출할 수 있고 항상 유효한 토큰을 얻을 수 있는 원자 함수를 제공할 수 있습니다.
/*
The non-atomic refresh function
*/
const refreshToken = async () => {
// Do whatever you need to do here ...
}
/*
Promise locking-queueing structure
*/
var promiesCallbacks = [];
const resolveQueue = value => {
promiesCallbacks.forEach(x => x.resolve(value));
promiesCallbacks = [];
};
const rejectQueue = value => {
promiesCallbacks.forEach(x => x.reject(value));
promiesCallbacks = [];
};
const enqueuePromise = () => {
return new Promise((resolve, reject) => {
promiesCallbacks.push({resolve, reject});
});
};
/*
The atomic function!
*/
var actionInProgress = false;
const refreshTokenAtomically = () => {
if (actionInProgress) {
return enqueuePromise();
}
actionInProgress = true;
return refreshToken()
.then(({ access }) => {
resolveQueue(access);
return access;
})
.catch((error) => {
rejectQueue(error);
throw error;
})
.finally(() => {
actionInProgress = false;
});
};
여기에도 게재 : https://stackoverflow.com/a/68154638/683763
언급URL : https://stackoverflow.com/questions/36948557/how-to-use-redux-to-refresh-jwt-token
'source' 카테고리의 다른 글
XMLHttpRequest 상태 0(응답 텍스트가 비어 있음) (0) | 2023.02.26 |
---|---|
로드 시 메서드를 한 번만 호출하는 응답 (0) | 2023.02.26 |
탭 탐색기를 사용하여 화면 구성 요소에 소품을 전달하는 방법 (0) | 2023.02.26 |
img 태그 문제를 url 및 클래스로 대응 (0) | 2023.02.26 |
iframe을 사용하여 Asynchronous(AJAX) 파일을 업로드하는 방법 (0) | 2023.02.26 |