用 redux async thunk 替换 S3Client 中的模拟凭据
Replace mock credentials in S3Client with redux async thunk
我有一个带有 redux 的类似 S3 的反应应用程序。我正在为 JS 使用 AWS SDK v3,并像这样初始化我的客户端:
auth.js
export const s3Client = new S3Client({
region: 'default',
credentials: {
accessKeyId: 'testTestAccess',
secretAccessKey: 'testTestSecret'
},
endpoint: `${document.URL}s3/`
});
我的请求通过我们的代理,这就是为什么我可以像上面的代码一样留下凭据,所以它可以是任何字符串。但我使用的是 s3 签名 url,它在查询字符串中使用凭据。
这就是我使用 redux-thunk 发送请求的方式
authReducer.js
const initialState = {
secretKey: 'initSecretKey',
accessKey: 'initAccessKey',
keysCreated: false
};
export const fetchKeys = createAsyncThunk(
'auth/fetchKeys',
async (_, { rejectWithValue }) => {
try {
const response = await axiosInstance.get();
if (response.statusText !== 'OK') {
throw new Error('Error!');
}
return response.data.secrets;
} catch (error) {
return rejectWithValue(error.message);
}
}
);
export const authSlice = createSlice({
name: 'auth',
initialState,
extraReducers: {
[fetchKeys.pending]: (state, action) => {
console.log('PENDING...');
},
[fetchKeys.fulfilled]: (state, action) => {
const { AccessKey, SecretKey } = action.payload;
state.secretKey = SecretKey;
state.accessKey = AccessKey;
state.keysCreated = true;
},
[fetchKeys.rejected]: (state, action) => {
console.log('ERROR');
}
},
reducers: {
setSecretKey: (state, action) => ({
...state,
secretKey: action.payload
}),
setAccessKey: (state, action) => ({
...state,
accessKey: action.payload
}),
setKeysCreated: (state, action) => ({
...state,
keysCreated: action.payload
})
}
});
export const { setSecretKey, setAccessKey, setKeysCreated } =
authSlice.actions;
export default authSlice.reducer;
MainPage.jsx
const MainPage = () => {
const dispatch = useDispatch();
const { keysCreated } = useSelector((state) => state.authReducer);
useEffect(() => {
dispatch(fetchKeys());
}, [dispatch]);
if (keysCreated) {
return <Content />
}
return <Loader />
};
那么我想做什么:
- 当页面呈现时,我使用 axios 和 redux-thunk 向 keygen 发送一个异步请求
- 仅当我获得密钥时才显示页面
- (!) 当请求成功时,用来自 keygen 的新密钥替换 s3 客户端实例中的模拟密钥,这样我就可以签名 urls.
我该怎么做?我只从商店拿到钥匙一次,所以看起来我需要订阅更改
const { secretKey, accessKey } = store.getState().authReducer;
export const s3Client = new S3Client({
credentials: {
accessKeyId: accessKey, // 'initAccessKey' from initial state
secretAccessKey: secretKey // 'initSecretKey' from initial state
}
});
我用 hook 解决了我的问题。
auth.js
export const s3Client = new S3Client({
region: 'default',
credentials: {
accessKeyId: 'initAccessKey',
secretAccessKey: 'initSecretKey'
}
});
export const useS3Client = () => {
const { accessKey, secretKey, keysCreated } = useSelector(
(state) => state.authReducer
);
const client = useMemo(() => {
if (keysCreated) {
return new S3Client({
region: 'default',
credentials: {
accessKeyId: accessKey,
secretAccessKey: secretKey
}
});
}
return s3Client;
}, [accessKey, secretKey, keysCreated]);
return [client, keysCreated];
};
我为 API 签名请求更改了一些功能:
// i added client as 1st argument
export const getUrl = async (client, object, expirationSec = 300) => {
const { name, absolutePath, parentBucket } = object;
const params = {
Bucket: parentBucket,
Key: absolutePath
};
return await getSignedUrl(client, new GetObjectCommand(params), {
expiresIn: expirationSec
}).catch((error) => setError(error, 'SIGNED URL GETTING FAILED'));
}
然后我可以在我的组件中使用它:
MainPage.jsx
const MainPageContainer = () => {
const dispatch = useDispatch();
const [, keysCreated] = useS3Client();
useEffect(() => {
dispatch(fetchKeys());
}, [dispatch]);
if (!keysCreated) return <Loader />;
return <MainPage />;
};
SignUrlForm.jsx
const SignUrlForm = () => {
const [client] = useS3Client();
const onGetSignedUrlClick = (object) => {
getUrl(client, object, intevalSec).then((url) => {
// some actions
});
};
return <Button onClick={onGetSignedUrlClick}>Sign URL</Button>;
};
我有一个带有 redux 的类似 S3 的反应应用程序。我正在为 JS 使用 AWS SDK v3,并像这样初始化我的客户端:
auth.js
export const s3Client = new S3Client({
region: 'default',
credentials: {
accessKeyId: 'testTestAccess',
secretAccessKey: 'testTestSecret'
},
endpoint: `${document.URL}s3/`
});
我的请求通过我们的代理,这就是为什么我可以像上面的代码一样留下凭据,所以它可以是任何字符串。但我使用的是 s3 签名 url,它在查询字符串中使用凭据。
这就是我使用 redux-thunk 发送请求的方式
authReducer.js
const initialState = {
secretKey: 'initSecretKey',
accessKey: 'initAccessKey',
keysCreated: false
};
export const fetchKeys = createAsyncThunk(
'auth/fetchKeys',
async (_, { rejectWithValue }) => {
try {
const response = await axiosInstance.get();
if (response.statusText !== 'OK') {
throw new Error('Error!');
}
return response.data.secrets;
} catch (error) {
return rejectWithValue(error.message);
}
}
);
export const authSlice = createSlice({
name: 'auth',
initialState,
extraReducers: {
[fetchKeys.pending]: (state, action) => {
console.log('PENDING...');
},
[fetchKeys.fulfilled]: (state, action) => {
const { AccessKey, SecretKey } = action.payload;
state.secretKey = SecretKey;
state.accessKey = AccessKey;
state.keysCreated = true;
},
[fetchKeys.rejected]: (state, action) => {
console.log('ERROR');
}
},
reducers: {
setSecretKey: (state, action) => ({
...state,
secretKey: action.payload
}),
setAccessKey: (state, action) => ({
...state,
accessKey: action.payload
}),
setKeysCreated: (state, action) => ({
...state,
keysCreated: action.payload
})
}
});
export const { setSecretKey, setAccessKey, setKeysCreated } =
authSlice.actions;
export default authSlice.reducer;
MainPage.jsx
const MainPage = () => {
const dispatch = useDispatch();
const { keysCreated } = useSelector((state) => state.authReducer);
useEffect(() => {
dispatch(fetchKeys());
}, [dispatch]);
if (keysCreated) {
return <Content />
}
return <Loader />
};
那么我想做什么:
- 当页面呈现时,我使用 axios 和 redux-thunk 向 keygen 发送一个异步请求
- 仅当我获得密钥时才显示页面
- (!) 当请求成功时,用来自 keygen 的新密钥替换 s3 客户端实例中的模拟密钥,这样我就可以签名 urls.
我该怎么做?我只从商店拿到钥匙一次,所以看起来我需要订阅更改
const { secretKey, accessKey } = store.getState().authReducer;
export const s3Client = new S3Client({
credentials: {
accessKeyId: accessKey, // 'initAccessKey' from initial state
secretAccessKey: secretKey // 'initSecretKey' from initial state
}
});
我用 hook 解决了我的问题。
auth.js
export const s3Client = new S3Client({
region: 'default',
credentials: {
accessKeyId: 'initAccessKey',
secretAccessKey: 'initSecretKey'
}
});
export const useS3Client = () => {
const { accessKey, secretKey, keysCreated } = useSelector(
(state) => state.authReducer
);
const client = useMemo(() => {
if (keysCreated) {
return new S3Client({
region: 'default',
credentials: {
accessKeyId: accessKey,
secretAccessKey: secretKey
}
});
}
return s3Client;
}, [accessKey, secretKey, keysCreated]);
return [client, keysCreated];
};
我为 API 签名请求更改了一些功能:
// i added client as 1st argument
export const getUrl = async (client, object, expirationSec = 300) => {
const { name, absolutePath, parentBucket } = object;
const params = {
Bucket: parentBucket,
Key: absolutePath
};
return await getSignedUrl(client, new GetObjectCommand(params), {
expiresIn: expirationSec
}).catch((error) => setError(error, 'SIGNED URL GETTING FAILED'));
}
然后我可以在我的组件中使用它:
MainPage.jsx
const MainPageContainer = () => {
const dispatch = useDispatch();
const [, keysCreated] = useS3Client();
useEffect(() => {
dispatch(fetchKeys());
}, [dispatch]);
if (!keysCreated) return <Loader />;
return <MainPage />;
};
SignUrlForm.jsx
const SignUrlForm = () => {
const [client] = useS3Client();
const onGetSignedUrlClick = (object) => {
getUrl(client, object, intevalSec).then((url) => {
// some actions
});
};
return <Button onClick={onGetSignedUrlClick}>Sign URL</Button>;
};