我已经按照 Expo 的指南设置了一个基本登录页面,该页面从我已经设置的 AWS Cognito 用户池中登录用户。这个基本登录页面似乎适用于我的 iPhone 上的 Expo Go 登录和注销功能,但在我的桌面上的浏览器上无法正常工作。我已将问题归结为“useAuthRequest”函数在从 AWS Cognito 打开托管登录页面后立即返回“dismiss”类型的响应。即使用户输入正确的凭据并登录,他们也只会看到一个新的弹出窗口,打开 expo 应用程序的主页。
这是网络上的(行为不当)登录流程:
首先,单击蓝色登录按钮后,用户会看到 AWS Cognito 托管的 UI。
输入正确的凭据后,弹出页面将继续向我们显示主页的副本。这不应该发生。通常,一旦用户输入凭证,托管的 UI 弹出窗口就会关闭,并且我们应该有一个“成功”的 AuthSession 响应,我们可以在其中将来自 AWS 的授权代码交换为 authToken,所有这些都在 useEffect 中触发。正如第 2 阶段的图像所示,我们do从 AWS Cognito 获取带有“code”和“state”参数的重定向,但交换并未发生。这是因为从用户打开 AWS 托管 UI 的那一刻起,“useAuthRequest”中的“response”输出就设置为 response.type = 'dismiss'。通常,响应类型应该是“成功”,我们可以从所述响应中获取代码并进行代币交换(这在 Expo Go 上运行良好,但在网络上则不行)。
我非常有信心这不是需要在 AWS Cognito 端修复的问题,因为我们从 Cognito 获得了正确的授权代码 - 我们只是不触发令牌交换,因为 useAuthRequest 响应被设置为“关闭”。
我想了解为什么使用“useAuthRequest”登录在网络上失败,但仍在 Expo Go 上工作。此外,该项目不使用任何 AWS Amplify。此外,虽然我不确定这对身份验证行为有何影响,但该项目使用了 Expo Router。
我将在下面提供我的代码:它实际上是 Expo 指南的一对一复制品,减去注销功能,并用 Typescript 编写:
import {
AccessTokenRequestConfig,
ResponseType,
TokenResponse,
exchangeCodeAsync,
makeRedirectUri,
revokeAsync,
useAuthRequest,
} from "expo-auth-session";
import React from "react";
import { StyleSheet, Button, Alert } from "react-native";
const clientId = process.env.EXPO_PUBLIC_COGNITO_CLIENT_ID!;
const userPoolUrl = process.env.EXPO_PUBLIC_COGNITO_USER_POOL!;
const redirectUri = makeRedirectUri();
export default function App() {
const [authTokens, setAuthTokens] = React.useState<TokenResponse | null>(
null
);
const discoveryDocument = React.useMemo(
() => ({
authorizationEndpoint: userPoolUrl + "/oauth2/authorize",
tokenEndpoint: userPoolUrl + "/oauth2/token",
revocationEndpoint: userPoolUrl + "/oauth2/revoke",
}),
[]
);
const [request, response, promptAsync] = useAuthRequest(
{
clientId,
responseType: ResponseType.Code,
redirectUri,
usePKCE: true,
},
discoveryDocument
);
React.useEffect(() => {
const exchangeFn = async (exchangeTokenReq: AccessTokenRequestConfig) => {
try {
const exchangeTokenResponse = await exchangeCodeAsync(
exchangeTokenReq,
discoveryDocument
);
setAuthTokens(exchangeTokenResponse);
} catch (error) {
console.error(error);
}
};
if (response) {
console.log("response type: " + response.type); // Web: response.type is always 'dismiss'
if (response.type === "error") {
Alert.alert(
"Authentication error",
response.params.error_description || "something went wrong"
);
return;
}
if (response.type === "success" && request?.codeVerifier) {
exchangeFn({
clientId,
code: response.params.code,
redirectUri,
extraParams: {
code_verifier: request.codeVerifier,
},
});
}
}
}, [discoveryDocument, request, response]);
console.log("authTokens: " + JSON.stringify(authTokens));
return authTokens ? (
<Button title="Logout" />
) : (
<Button disabled={!request} title="Login" onPress={() => promptAsync()} />
);
}
我也面临着类似的确保处理与认知连接的通信,它可以在expo go上工作,但在构建之后不起作用,这使得调试变得困难。