UseAuth : AWSは、Auth +反応フックを簡単にします
36820 ワード
これは、サンプルの実装を提供する短いポストですAWS Amplify authentication management フックで反応アプリで.
時Auth.signIn() 成功すると、Auth.currentSession() . これはよく文書化されていないようですが、ブラウザのリフレッシュ時に認証状態を保持する能力を解除します. 生source code and tests . 叫ぶuseHooks.com インスピレーションを求めて 叫ぶKent C. Dodds 反応フックテスト戦略と実施に関するインスピレーションのために.
この記事によって対処される望ましい結果は、Auth Management戦略です. それがすべてのコンポーネントに容易に手に入るように、中心的にAuth状態を管理します. このフックは、フックの構文を使用します. 認証サービスはAWS増幅(フードの下のAWS認知)です. をテストする. 私がAWAVEアンプで私の初期の時間で見つけた1つのものは、ブラウザーリフレッシュで、私のアプリが現在の認証状態を失うだろうということです.一言で言えば、ログインしたユーザーがブラウザのリフレッシュにログインします.そしてそれは迷惑です.
その上、私はこの問題についてあまり書かれていませんでした.AWSドキュメントで重要なラインを逃したのは全く可能ですが
多くの擬似コードが、あなたはアイデアを得る.
それは抽象的なフックをテストするのに完全に可能です、しかし、ケントC .ドッズはそれが自然の生息地でフックをテストするのがより良いと私に確信させました.コンポーネント.
基本的に、フックを使用する例のコンポーネントを設定し、フックによってのみ実現できるコンポーネントの状態を期待します.
TLドクター
useAuth
フックのソースコード.問題
この記事によって対処される望ましい結果は、Auth Management戦略です.
その上、私はこの問題についてあまり書かれていませんでした.AWSドキュメントで重要なラインを逃したのは全く可能ですが
Auth.currentSession()
アクセスされたセッションクッキーは、ブラウザで保持された主要なエピファニーだった.フック
// use-auth.js
import React, {
useState, useEffect, useContext, createContext,
} from 'react';
import { Auth } from '@aws-amplify/auth';
// Implement your particular AWS Amplify configuration
const amplifyConfigurationOptions = {
userPoolRegion: "REGION",
userPoolId: "POOL_ID",
userPoolWebClientId: "CLIENT_ID",
};
Auth.configure(amplifyConfigurationOptions);
const AuthContext = createContext();
// Wrap your app with <ProvideAuth />
export function ProvideAuth({ children }) {
const auth = useProvideAuth();
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
}
// Access auth values and functions with custom useAuth hook
export const useAuth = () => useContext(AuthContext);
function useProvideAuth() {
const [user, setUser] = useState(null);
const [isSignedIn, setIsSignedIn] = useState(false);
useEffect(() => {
// NOTE: check for user or risk an infinite loop
if (!user) {
// On component mount
// If a session cookie exists
// Then use it to reset auth state
Auth.currentSession()
.then((session) => {
const {
idToken,
accessToken,
} = session;
// Define your user schema per your needs
const user = {
email: idToken.payload.email,
username: idToken.payload.preferred_username,
userId: idToken.payload.sub,
accessToken: accessToken.jwtToken,
};
setIsSignedIn(true);
setUser(user);
})
.catch((err) => {
// handle it
});
}
}, [user]);
const signIn = ({ email, password }) => Auth.signIn(email, password)
.then((cognitoUser) => {
// Set user data and access token to memory
const {
attributes,
signInUserSession: {
accessToken,
},
} = cognitoUser;
const user = {
email: attributes.email,
username: attributes.preferred_username,
userId: attributes.sub,
accessToken: accessToken.jwtToken,
};
setIsSignedIn(true);
setUser(user);
return user;
});
const signOut = () => Auth.signOut()
.then(() => {
setIsSignedIn(false);
setUser(null);
});
return {
user,
isSignedIn,
signIn,
signOut,
};
}
それが来るとき、私は認められたneophyteですuseEffect
, それで、このコールバックの中でauth状態を回復するためのより良い実現があるかもしれません.特に、私は最初に無限ループにsetUser()
だってuser
はコールバックの依存関係の一つです.この1つのアドバイスを聞いて満足.使い方
多くの擬似コードが、あなたはアイデアを得る.
// AppRoot.jsx
import React from 'react';
import App from './app'; // uses <MyComponent />
import { ProvideAuth } from './use-auth';
return (
<ProvideAuth>
<App />
</ProvideAuth>
);
// MyComponent.jsx
import React from 'react';
import { useAuth } from './use-auth';
function MyComponent() {
const { isSignedIn, user, signIn, signOut } = useAuth();
return (
<div>
<div>{`IsSignedIn: ${isSignedIn}`}</div>
<div>{`Username: ${user?.username}`}</div>
{isSignedIn ? (
<button onClick={signOut} type="button">Sign Out</button>
) : (
<button onClick={signIn} type="button">Sign In</button>
)}
</div>
)
};
テスト
それは抽象的なフックをテストするのに完全に可能です、しかし、ケントC .ドッズはそれが自然の生息地でフックをテストするのがより良いと私に確信させました.コンポーネント.
基本的に、フックを使用する例のコンポーネントを設定し、フックによってのみ実現できるコンポーネントの状態を期待します.
// Example Component
import React from 'react';
import { ProvideAuth, useAuth } from '../src/use-auth';
function TestComponent() {
const {
user,
isSignedIn,
signIn,
signOut,
} = useAuth();
const handleSignIn = () => {
const mockCreds = {
email: '[email protected]',
password: 'pw',
}
signIn(mockCreds);
}
const handleSignOut = () => signOut()
return (
<div>
<div>{`IsSignedIn: ${isSignedIn}`}</div>
<div>{`Username: ${user?.username}`}</div>
<div>{`AccessToken: ${user?.accessToken}`}</div>
<button onClick={handleSignIn} type="button">SignInButton</button>
<button onClick={handleSignOut} type="button">SignOutButton</button>
</div>
);
}
function UseAuthExample() {
return (
<ProvideAuth>
<TestComponent />
</ProvideAuth>
);
}
export { UseAuthExample };
// use-auth.test.jsx
import React from 'react';
import {
render, screen, fireEvent, act,
} from '@testing-library/react';
import { Auth } from '@aws-amplify/auth';
import { UseAuthExample } from './UseAuthExample';
describe('useAuth', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should provide default values on load when user is not authenticated', () => {
const currentSessionMock = jest.fn().mockRejectedValue('No user found.');
Auth.currentSession = currentSessionMock;
render(<UseAuthExample />);
const isSignedIn = screen.getByText(/issignedin/i);
const username = screen.getByText(/username/i);
const accessToken = screen.getByText(/accesstoken/i);
expect(isSignedIn).toHaveTextContent('IsSignedIn: false');
expect(username).toHaveTextContent('Username:');
expect(accessToken).toHaveTextContent('AccessToken:');
});
it('should provide current user on load when current session is found', async () => {
const currentSessionMock = jest.fn().mockResolvedValue({
idToken: {
payload: {
email: '[email protected]',
preferred_username: 'myuser',
sub: '1234-abcd',
},
},
accessToken: {
jwtToken: 'fake-token',
},
});
Auth.currentSession = currentSessionMock;
await act(async () => {
render(<UseAuthExample />);
});
const isSignedIn = screen.getByText(/issignedin/i);
const username = screen.getByText(/username/i);
const accessToken = screen.getByText(/accesstoken/i);
expect(isSignedIn).toHaveTextContent('IsSignedIn: true');
expect(username).toHaveTextContent('Username: myuser');
expect(accessToken).toHaveTextContent('AccessToken: fake-token');
});
it('should login the user and update ui', async () => {
const currentSessionMock = jest.fn().mockRejectedValue('No user found.');
const signInMock = jest.fn().mockResolvedValue({
attributes: {
email: '[email protected]',
preferred_username: 'myuser',
sub: '1234-abcd',
},
signInUserSession: {
accessToken: {
jwtToken: 'fake-token',
},
},
});
Auth.currentSession = currentSessionMock;
Auth.signIn = signInMock;
render(<UseAuthExample />);
const isSignedIn = screen.getByText(/issignedin/i);
const username = screen.getByText(/username/i);
const accessToken = screen.getByText(/accesstoken/i);
expect(isSignedIn).toHaveTextContent('IsSignedIn: false');
expect(username).toHaveTextContent('Username:');
expect(accessToken).toHaveTextContent('AccessToken:');
const signInButton = screen.getByText(/signinbutton/i);
await act(async () => {
fireEvent.click(signInButton);
});
expect(isSignedIn).toHaveTextContent('IsSignedIn: true');
expect(username).toHaveTextContent('Username: myuser');
expect(accessToken).toHaveTextContent('AccessToken: fake-token');
});
});
Reference
この問題について(UseAuth : AWSは、Auth +反応フックを簡単にします), 我々は、より多くの情報をここで見つけました https://dev.to/kwhitejr/useauth-aws-amplify-auth-react-hooks-easy-auth-management-2honテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol