我可以在不违反 React 设计原则的情况下在 reducer 中验证令牌吗?
Can I verify token in reducer without violating React design principles?
我正在尝试使用 react/redux 找出我的 jwt 令牌身份验证的结构。我现在设置它的方式是,我使用一个中间件在调度动作 ATTEMPT_LOGIN_SUCCESS 时将令牌保存在本地存储中(注意:本地存储的安全性不是重点)。
对于用户是否登录的初始状态,我目前从本地存储中获取令牌并在我的登录减速器中验证它。我的问题是我是否确实应该把那个逻辑放在那个地方。
用于保存令牌的 jwt-handler 中间件:
import {ATTEMPT_LOGIN_SUCCESS} from "./dataTypes/login"
const jwtHandler = store => next => action => {
switch(action.type){
case ATTEMPT_LOGIN_SUCCESS:
const token = action.payload;
localStorage.setItem("token", token);
}
return next(action);
}
export default jwtHandler;
登录reducer(有问题的代码是从top到初始状态):
import {
ATTEMPT_LOGIN_BEGIN, ATTEMPT_LOGIN_FAIL, ATTEMPT_LOGIN_SUCCESS
} from "../dataTypes/login";
import authenticateToken from "./authenticateToken";
const token = localStorage.getItem("token");
const isValid = authenticateToken(token); //Decodes and checks date to ensure valid
if(!isValid){
localStorage.setItem("token", "");
}
const initialState = {
loading:false,
errorMessage: "",
success:false,
isLoggedIn: isValid
};
const loginReducer = (state = initialState, action) => {
switch (action.type) {
case ATTEMPT_LOGIN_BEGIN:
return {
...state,
loading:true,
errorMessage:""
};
case ATTEMPT_LOGIN_SUCCESS:
return {
...state,
loading:false,
success:true,
token:action.payload
};
case ATTEMPT_LOGIN_FAIL:
return {
...state,
loading:false,
errorMessage:action.payload
};
default:
return state;
}
};
export default loginReducer;
我觉得可能有更好的地方来放置我的登录逻辑,但我还没有在网上找到好的答案。
在你的reducer中你可以做
const INITIAL_STATE = {
// ...data
loading:false,
token: localStorage.getItem("token"),
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ATTEMPT_LOGIN_BEGIN:
return {
...state,
loading: true,
};
case ATTEMPT_LOGIN_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
loading: false,
token: action.payload.token,
};
case ATTEMPT_LOGIN_FAILURE:
localStorage.removeItem("token");
return {
...state,
loading: false,
token: null,
};
}
}
我更喜欢你的中间件模式,但更集中一点:
注意:这是自以为是的,只是一个示例草图
// middleware.js
import {
INIT_SESSION, ATTEMPT_LOGIN_BEGIN, ATTEMPT_LOGIN_FAIL, ATTEMPT_LOGIN_SUCCESS, LOGOUT
} from "../dataTypes/login";
import authenticateToken from "./authenticateToken";
const jwtHandler = store => next => action => {
switch(action.type){
// INIT_SESSION handled only here not in any reducer
case INIT_SESSION:
const token = localStorage.getItem("token");
const isValid = authenticateToken(token);
if(valid){
store.dispatch({type:ATTEMPT_LOGIN_SUCCESS, payload: token});
} else {
localStorage.removeItem("token");
}
break;
case ATTEMPT_LOGIN_SUCCESS:
const newToken = action.payload;
localStorage.setItem("token", newToken);
break;
case LOGOUT:
localStorage.removeItem("token");
break;
default:
}
return next(action);
}
export default jwtHandler;
// index.js
const store = createStore();
store.dispatch({type: INIT_SESSION});
ReactDOM.render(<Provider store={store}>//...
// reducer.js stays clean...
我正在尝试使用 react/redux 找出我的 jwt 令牌身份验证的结构。我现在设置它的方式是,我使用一个中间件在调度动作 ATTEMPT_LOGIN_SUCCESS 时将令牌保存在本地存储中(注意:本地存储的安全性不是重点)。
对于用户是否登录的初始状态,我目前从本地存储中获取令牌并在我的登录减速器中验证它。我的问题是我是否确实应该把那个逻辑放在那个地方。
用于保存令牌的 jwt-handler 中间件:
import {ATTEMPT_LOGIN_SUCCESS} from "./dataTypes/login"
const jwtHandler = store => next => action => {
switch(action.type){
case ATTEMPT_LOGIN_SUCCESS:
const token = action.payload;
localStorage.setItem("token", token);
}
return next(action);
}
export default jwtHandler;
登录reducer(有问题的代码是从top到初始状态):
import {
ATTEMPT_LOGIN_BEGIN, ATTEMPT_LOGIN_FAIL, ATTEMPT_LOGIN_SUCCESS
} from "../dataTypes/login";
import authenticateToken from "./authenticateToken";
const token = localStorage.getItem("token");
const isValid = authenticateToken(token); //Decodes and checks date to ensure valid
if(!isValid){
localStorage.setItem("token", "");
}
const initialState = {
loading:false,
errorMessage: "",
success:false,
isLoggedIn: isValid
};
const loginReducer = (state = initialState, action) => {
switch (action.type) {
case ATTEMPT_LOGIN_BEGIN:
return {
...state,
loading:true,
errorMessage:""
};
case ATTEMPT_LOGIN_SUCCESS:
return {
...state,
loading:false,
success:true,
token:action.payload
};
case ATTEMPT_LOGIN_FAIL:
return {
...state,
loading:false,
errorMessage:action.payload
};
default:
return state;
}
};
export default loginReducer;
我觉得可能有更好的地方来放置我的登录逻辑,但我还没有在网上找到好的答案。
在你的reducer中你可以做
const INITIAL_STATE = {
// ...data
loading:false,
token: localStorage.getItem("token"),
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ATTEMPT_LOGIN_BEGIN:
return {
...state,
loading: true,
};
case ATTEMPT_LOGIN_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
loading: false,
token: action.payload.token,
};
case ATTEMPT_LOGIN_FAILURE:
localStorage.removeItem("token");
return {
...state,
loading: false,
token: null,
};
}
}
我更喜欢你的中间件模式,但更集中一点:
注意:这是自以为是的,只是一个示例草图
// middleware.js
import {
INIT_SESSION, ATTEMPT_LOGIN_BEGIN, ATTEMPT_LOGIN_FAIL, ATTEMPT_LOGIN_SUCCESS, LOGOUT
} from "../dataTypes/login";
import authenticateToken from "./authenticateToken";
const jwtHandler = store => next => action => {
switch(action.type){
// INIT_SESSION handled only here not in any reducer
case INIT_SESSION:
const token = localStorage.getItem("token");
const isValid = authenticateToken(token);
if(valid){
store.dispatch({type:ATTEMPT_LOGIN_SUCCESS, payload: token});
} else {
localStorage.removeItem("token");
}
break;
case ATTEMPT_LOGIN_SUCCESS:
const newToken = action.payload;
localStorage.setItem("token", newToken);
break;
case LOGOUT:
localStorage.removeItem("token");
break;
default:
}
return next(action);
}
export default jwtHandler;
// index.js
const store = createStore();
store.dispatch({type: INIT_SESSION});
ReactDOM.render(<Provider store={store}>//...
// reducer.js stays clean...