前面对AWS Amplify进行一个基本的介绍,以及如何为React APP添加用户验证,使用S3存储的功能,使用AWS API功能。下面介绍如何使用Amplify自定义用户验证功能。

AWS Amplify系列教程:
- AWS Amplify系列之一:简介
- AWS Amplify系列之二:增加验证功能
- AWS Amplify系列之三:增加文件存储功能
- AWS Amplify系列之四:增加API功能
- AWS Amplify系列之五:自定制验证功能
- AWS Amplify教程之:Google OAuth登录
设定条件路由
由于需要针对登录/未登录用户进行不同的控制,因此需要使用路由。首先安装依赖库:
yarn add react-router-dom
然后在App.js中,设定条件路由:
import { Switch, Route, BrowserRouter as Router } from 'react-router-dom';
return(
<Router>
<div className="App">
<Header/>
<Switch>
<Route exact path='/'>
<StudentList/>
</Route>
</Switch>
</div>
</Router>
)
移除withAuthenticator,改为人工控制登录状态
删除以下语句中的withAuthenticator,后面将自己管理是否已经登录的状态:
export default withAuthenticator(App);
更新App.js:
function App() {
const [loggedin, setLoggedin] = usedState(false);
const isLoggedIn = () => {
Auth.currentAuthenticatedUser().then(() => {
setLoggedin(true);
}).catch(() => {
setLoggedin(false);
})
}
useEffect(() => {
isLoggedIn();
}, [])
}
同时更新自定义的signOut函数:
const signOut = async () => {
try {
await Auth.signOut();
setLoggedin(false);
} catch (err) {
console.log(err);
}
}
同时可以更新Header:
{loggedin? (
<Button onClick={signOut}>
Sign Out
</Button>
) : (
<Link to="/signin">
<Button>
Sign In
</Button>
</Link>
)}
在App.js中,添加Sign in组件路由:
const onSignIn = () => {
setLoggedIn(true);
}
...
<Switch>
<Route path="/signin">
<SignIn onSignIn={onSignIn}/>
</Route>
</Switch>
SignIn组件:
import React from 'react'
import { Button, TextField } from '@material-ui/core';
import { useHistory } from 'react-route-dom';
const SignIn = ({ onSignIn }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const history = useHistory();
const signIn = async () => {
try {
const user = await Auth.signIn(username, password);
history.push('/');
onSignIn();
} catch (err) {
console.log(err);
}
}
return (
<div className="signin">
<TextField id='username'
label="Username"
value={username}
onChange={e => setUsername(e.target.value)}
/>
<TextField id='password'
label="Password"
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<Button id="signinBtn" onClick="signIn">
Sign In
</Button>
</div>
)
}
export default SignIn
对未登录用户进行访问控制
amplify update auth
Walk through all configuration
- Allow unauthenticated logins? Yes
其余选项都选择默认设置
amplify push
在AWS控制台更新配置
进入Cognito -> Identity Pool -> Edit Identify pool -> Unauthenticated role
进入IAM,找到Unauthenticated role -> Permissions -> Attach policies -> Add inline policy -> JSON
然后以下模板更新policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "appsync:GraphQL",
"Resource": "arn:aws:appsync:<REGION>:<ACCOUNT>:apis/<APP ID>/types/<Query | Mutation>/fields/<METHOD>"
}
]
}
比如这样将允许未授权用户调用listStudents方法:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "appsync:GraphQL",
"Resource": "arn:aws:appsync:eu-west-1:YOUR_AWS_ACCOUNT_ID:apis/YOUR_APP_SYNC_APP_ID/types/Query/fields/listStudents"
}
]
}
同时还可以定义类似的policy,比如对S3的访问:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3::::<BUCKET>/public"
}
]
}
然后单击“Review Policy”, 输入名字后保存。
回到AWS AppSync控制台,将”Default authorization model”更改为”AWS Identity and Access Management (IAM)”,保存。
更新代码
这时需要将前面的fetchStudents方法由:
const studentData = await API.graphql(graphqlOperation(listStudents));
更新为:
const studentData = await API.graphql({
query: listStudents,
authMode: 'AWS_IAM'
});
但这时会有一个问题,登录的用户反倒无法访问相应资源了。
进入IAM,找到authorizedRole,”Public_policy_xxxxx”
可以发现,这里缺少对AppSync访问的授权。
同样,添加相应的Policy就可以了:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "appsync:GraphQL",
"Resource": [
"arn:aws:appsync:eu-west-1:YOUR_AWS_ACCOUNT_ID:apis/YOUR_APP_SYNC_APP_ID/types/Query/fields/listStudents",
"arn:aws:appsync:eu-west-1:YOUR_AWS_ACCOUNT_ID:apis/YOUR_APP_SYNC_APP_ID/types/Mutation/fields/createStudent",
"arn:aws:appsync:eu-west-1:YOUR_AWS_ACCOUNT_ID:apis/YOUR_APP_SYNC_APP_ID/types/Mutation/fields/updateStudent"
]
}
]
}
同理,在应用程序中调用mutation时,还需要更新为:
await API.graphql({
query: updateStudent,
variables: {input: student},
authMode: 'AWS_IAM'
})