问题:
每次登录时,Auth.signIn 获取的 id 令牌都会存储在 localStorage 中。
登录后,UI 发出需要授权的请求(使用 id 令牌),
但每次都失败了。
我尝试在 localStorage 中复制 id 令牌并在 Postman 中尝试相同的 API 请求,
下面显示的错误消息。
the incoming token has expired
但是当我重新加载页面时,请求已成功发送并收到 ok 响应。
我不确定是否是因为我的代码中的令牌刷新逻辑不正确。
我只是将令牌刷新逻辑放在 App.js 的 componentDidMount() 中。
逻辑基于以下帖子。
how handle refresh token service in AWS amplify-js
有人可以让我知道我的代码有什么问题吗?
索引.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
//aws
import Amplify from 'aws-amplify';
import config from './config.json'
const Index = () => {
Amplify.configure({
Auth: {
mandatorySignId: true,
region: config.cognito.REGION,
userPoolId: config.cognito.USER_POOL_ID,
userPoolWebClientId: config.cognito.APP_CLIENT_ID
}
});
return(
<React.StrictMode>
<App/>
</React.StrictMode>
)
}
ReactDOM.render(
<Index />,
document.getElementById('root')
);
serviceWorker.unregister();
应用程序.js
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import { Redirect } from 'react-router';
import { withRouter } from 'react-router-dom';
import config from './config.json'
//Screen
import Login from './screen/auth/Login'
import Drawer from './components/Drawer'
import { Auth } from 'aws-amplify';
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
const CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool;
class App extends Component {
state = {
isAuthenticated: false,
isAuthenticating: true,
user: null
}
setAuthStatus = authenticated =>{
this.setState({isAuthenticated: authenticated})
}
setUser = user =>{
this.setState({ user: user})
}
handleLogout = async () =>{
try{
Auth.signOut();
this.setAuthStatus(false);
this.setUser(null)
localStorage.removeItem('jwtToken')
localStorage.removeItem('idToken')
this.props.history.push('/')
}catch(error){
console.log(error)
}
}
tokenRefresh(){
const poolData = {
UserPoolId : config.cognito.USER_POOL_ID, // Your user pool id here,
ClientId : config.cognito.APP_CLIENT_ID// Your client id here
};
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const cognitoUser = userPool.getCurrentUser();
cognitoUser.getSession((err, session) =>{
const refresh_token = session.getRefreshToken();
cognitoUser.refreshSession(refresh_token, (refErr, refSession) => {
if (refErr) {
throw refErr;
}
else{
localStorage.setItem('jwtToken',refSession.idToken.jwtToken)
localStorage.setItem('idToken',JSON.stringify(refSession.idToken))
}
});
})
}
async componentDidMount(){
try{
const session = await Auth.currentSession();
this.setAuthStatus(true);
const user = await Auth.currentAuthenticatedUser();
this.setUser(user);
}catch(error){
console.log(error);
}
// check if the token need refresh
this.setState({isAuthenticating: false})
let getIdToken = localStorage.getItem('idToken');
if(getIdToken !== null){
let newDateTime = new Date().getTime()/1000;
const newTime = Math.trunc(newDateTime);
const splitToken = getIdToken.split(".");
const decodeToken = atob(splitToken[1]);
const tokenObj = JSON.parse(decodeToken);
const newTimeMin = ((newTime) + (5 * 60)); //adding 5min faster from current time
if(newTimeMin > tokenObj.exp){
this.tokenRefresh();
}
}
}
render(){
const authProps = {
isAuthenticated: this.state.isAuthenticated,
user: this.state.user,
setAuthStatus: this.setAuthStatus,
setUser: this.setUser
}
return (
!this.state.isAuthenticating &&
<React.Fragment>
{this.state.isAuthenticated ?
<Drawer props={this.props} auth={authProps} handleLogout={this.handleLogout} onThemeChange={this.props.onThemeChange} /> :
<Switch>
<Redirect exact from='/' to='/login'/>
<Route path='/login' render={(props)=> <Login {...props} auth={authProps}/>} />
</Switch>
}
</React.Fragment>
);
}
}
export default withRouter(App);
登录.js
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
import withStyles from '@material-ui/core/styles/withStyles';
import _ from 'lodash';
import { Auth } from "aws-amplify";
function Login(props) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (event) => {
event.preventDefault();
const payload = {
"username": username,
"password": password
}
// aws login
try{
const signInResponse = await Auth.signIn(payload.username,payload.password)
console.log(signInResponse)
props.history.push("/home")
props.auth.setAuthStatus(true)
props.auth.setUser(signInResponse)
localStorage.setItem('jwtToken',signInResponse.signInUserSession.idToken.jwtToken)
localStorage.setItem('idToken',JSON.stringify(signInResponse.signInUserSession.idToken))
}catch(error){
console.log(error)
}
}
return(
<form onSubmit={handleSubmit}>
<TextField
name='username'
value="username"
...
/>
<TextField
name='password'
value="password"
...
/>
</form>
);
}
export default withStyles(styles)(Login);
为什么要在 AWS Amplify 为您处理令牌时自己刷新令牌?
该文件指出:
如果访问令牌超时(一小时后发生),Amplify 会自动尝试刷新。您可以在 Cognito 用户池控制台中配置刷新令牌过期时间。
Auth.currentSession()
返回一个CognitoUserSession
对象,其中包含 JWTaccessToken
、idToken
和refreshToken
。如果令牌过期并且出现有效的
accessToken
,此方法将自动刷新idToken
和refreshToken
。因此,如果需要,您可以使用此方法刷新会话。https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#managing-security-tokens https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#retrieve-current-session