2.1.0 • Published 5 years ago

@pcgbros/cognito-sdk-frontend v2.1.0

Weekly downloads
1
License
ISC
Repository
-
Last release
5 years ago

pbplus-cognito-frontend-sdk

安裝

npm 套件需求:

@pcgbros/session-sdk-frontend ^2.1.2 react ^16.5.2 react-dom ^16.5.2 react-redux ^5.0.7 react-router-dom ^4.3.1

使用 cognito (一):combineReducer

cognito sdk 需要 session sdk,這兩個 sdk 都和 redux 相依,第一步就是將 combineReducers 傳入的物件中加入這兩個 reducer。

import { PBPLUS_SESSION_REDUCER, pbplusSessionReducer } from '@pcgbros/session-sdk-frontend';
import { combineReducers } from 'redux';

import { PBPLUS_COGNITO_REDUCER, pbplusCognitoReducer } from '@pcgbros/cognito-sdk-frontend';

export default combineReducers({
  [PBPLUS_SESSION_REDUCER]: pbplusSessionReducer,
  [PBPLUS_COGNITO_REDUCER]: pbplusCognitoReducer
});

使用 cognito (二):

使用 cognito function 傳入 (cognitoConfig)(App Component),搭配 compose 可以把 HOC 過多層的寫法變得更簡略。

cognito sdk 需要 session id 作為現在使用者登入狀態的識別碼, sessionStart 負責初始現在使用者的 session id, cognito 才能依據 session id 向 server 請求登入資訊, 當然這兩個 sdk 都需要準備好各自的 config。

import sessionStart from '@pcgbros/session-sdk-frontend';
import cognito from '@pcgbros/cognito-sdk-frontend';
import React, { Component } from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';

import Navigator from './Navigator.js';
import RouteComponent from './RouteComponent.js';

export class App extends Component{
  render() {
    const { isLoading } = this.props;

    return (
      <React.Fragment>
        <Navigator />
        <RouteComponent />
        {
          isLoading ? 
          <i className="fa fa-2x fa-circle-o-notch fa-spin loading-icon"></i> : 
          null
        }
      </React.Fragment>
    );
  }
}

const sessionConfig = {
  baseURL: process.env.PBPLUS_SESSION.BASE_URL,
  clientId: process.env.PBPLUS_SESSION.CLIENT_ID,
  defaultSessionId: process.env.PBPLUS_SESSION.DEFAULT_SESSION_ID,
};

const cognitoConfig = { 
  authDomain: process.env.AWS_COGNITO.AUTH_DOMAIN,
  userPoolClientId: process.env.AWS_COGNITO.USER_POOL_CLIENT_ID, 
  cognitoBaseURL: process.env.AWS_COGNITO.BASE_URL
};

function mapStateToProps(store) {
  const { app } = store;
  const { isLoading } = app;

  return {
    isLoading,
  };
}

export default compose(
  sessionStart(sessionConfig),
  cognito(cognitoConfig),
  withRouter,
  connect(mapStateToProps)
)(App);

關於 cognito

cognito 會有兩個預設行為:

1 若從 cognito 登入頁面登入完成轉導回來時,會向 server 送出現在 session id 為登入狀態的請求,並轉導至到跳至 cognito 登入畫面前的頁面。

2 向 servier 請求現在 session id 的登入狀態,並寫到 reducer 中,可以藉由 getLoginStatusFromStore 取得現在的登入資訊。

cognito settings:

必填屬性: authDomain cognitoBaseURL userPoolClientId

getLoginStatusFromStore

取得 reducer 中的登入資訊

defaultState = {
  // 使用者是否為登入狀態
  isLoggedIn: false,
  // 向 server 請求登入狀態流程是否結束
  isLoginStatusInitialized: false,,
  // 向 server 請求登入的狀態 flag
  isFetchingLoginStatus: false,
  // 使用者的 cognito email
  email: '',
  // 使用者的 cognito username
  username: ''
};
// SomeComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getLoginStatusFromStore } from '@pcgbros/cognito-sdk-frontend'; 

export class SomeComponent extends Component {
  render() {
    const { isLoggedIn, email } = this.props;
    return (
        <main>
          <h1>登入狀態: { isLoggedIn ? '已登入' : '未登入' }</h1>
          <h1>使用者 email: {email}</h1>
        </main>
    );
  }
}

export default connect(store => {
  const loginStatus = getLoginStatusFromStore(store);
  return {
    isLoggedIn: loginStatus.isLoggedIn,
    email: loginStatus.email
  };
})(SomeComponent);

Other Actions

fetchLoginStatus

此為 redux action,手動取得現在 session id 對應的登入狀態,需傳入 cognito base url。

sample code:

import { fetchLoginStatus } from '@pcgbros/cognito-sdk-frontend';

dispatch(fetchLoginStatus(cognitoBaseUrl))

logout

此為 redux action,手動登出,這個 action 可以做四件事:

1 向 redis server 送出刪除 session 的請求 2 清空 cookie 的 session id 3 將 cognito reducer 中 loginStatus 的 isLoggedIn email username 設定為:

loginStatus = {
  isLoggedIn: false,
  email: '',
  username: ''
}

其他 flag 表留原本狀態。

4 自動轉導至 cognito 登入頁面,這個行為可以藉由傳入物件的 redirectToLoginPageAfterLogout property (boolean) 控制是否執行轉導。

sample code:

import { logout } from '@pcgbros/cognito-sdk-frontend';

const redirectArgs = {
    // config 設定的 cognito auth domain
    authDomain, 
    // config 設定的 cognito userPoolClientId
    userPoolClientId, 
    // 非必填,預設為 true
    redirectToLoginPageAfterLogout
};

dispatch(logout(sessionBaseUrl, redirectArgs))

resetLoginStatus

此為 redux action,手動重置 loginStatus 為初始狀態:

defaultState = {
  isLoggedIn: false,
  isLoginStatusInitialized: false,,
  isFetchingLoginStatus: false,
  email: '',
  username: ''
};

sample code:

import { resetLoginStatus } from '@pcgbros/cognito-sdk-frontend';

dispatch(resetLoginStatus())

redirectToLoginPage

手動轉導至登入頁,直接給參數呼叫即可,這不是 redux action。

sample code:

const redirectArgs = { authDomain: COGNITO_AUTH_DOMAIN, userPoolClientId: COGNITO_USER_POOL_CLIENT_ID };
redirectToLoginPage(redirectArgs);

將上面這些 actions 寫在 React Component 裡的 sample code:

import React, { Component } from 'react';
import { connect } from 'react-redux';

import { 
  logout, 
  getLoginStatusFromStore, 
  fetchLoginStatus, 
  redirectToLoginPage
} from '@pcgbros/cognito-sdk-frontend';

const { AUTH_DOMAIN, USER_POOL_CLIENT_ID, BASE_URL } = process.env.AWS_COGNITO;
const sessionBaseUrl = process.env.PBPLUS_SESSION.BASE_URL;

export class SomeComponent extends Component {
  constructor(props) {
    super(props);

    this.logoutWithoutRedirect = this.logoutWithoutRedirect.bind(this);
    this.fetchLoginStatus = this.fetchLoginStatus.bind(this);
    this.redirectToLoginPage = this.redirectToLoginPage.bind(this);
    this.logoutWithRedirect = this.logoutWithRedirect.bind(this);
  }

  logoutWithoutRedirect() {
    const redirectArgs = { 
      authDomain: AUTH_DOMAIN, 
      userPoolClientId: USER_POOL_CLIENT_ID, 
      redirectToLoginPageAfterLogout: false
    };
    this.props.logout(sessionBaseUrl, redirectArgs);
  }

  logoutWithRedirect() {
    const redirectArgs = { 
      authDomain: AUTH_DOMAIN, 
      userPoolClientId: USER_POOL_CLIENT_ID
    };
    this.props.logout(sessionBaseUrl, redirectArgs);
  }

  fetchLoginStatus() {
    this.props.fetchLoginStatus(BASE_URL);
  }

  redirectToLoginPage() {
    const redirectArgs = { authDomain: AUTH_DOMAIN, userPoolClientId: USER_POOL_CLIENT_ID };
    redirectToLoginPage(redirectArgs);
  }

  render() {
    const { loginStatus } = this.props;

    if (!loginStatus.isLoginStatusInitialized) {
      return null;
    }

    return (
      loginStatus.isLoggedIn ?
      <div>
        <a style={{display: 'block', textDecoration: 'underline', cursor: 'pointer'}} onClick={this.logoutWithoutRedirect}>登出 後在原頁</a>
        <a style={{display: 'block', textDecoration: 'underline', cursor: 'pointer'}} onClick={this.logoutWithRedirect}>登出 後回主頁</a>
        <a style={{display: 'block', textDecoration: 'underline', cursor: 'pointer'}} onClick={this.fetchLoginStatus}>重新抓取登入資訊,可以在 form submit 的時候重新驗證登入資訊</a>
      </div>
      : 
      <div>
        <a style={{display: 'block', textDecoration: 'underline', cursor: 'pointer'}} onClick={this.redirectToLoginPage}>登入</a>
        <a style={{display: 'block', textDecoration: 'underline', cursor: 'pointer'}} onClick={this.fetchLoginStatus}>重新抓取登入資訊,可以在 form submit 的時候重新驗證登入資訊</a>
      </div>
    );
  }
}


export default withRouter(connect(store => {
  const loginStatus = getLoginStatusFromStore(store);

  return {
    loginStatus
  };
}, dispatch => {
  return {
    logout: (sessionBaseUrl, redirectArgs) => {
      return dispatch(logout(sessionBaseUrl, redirectArgs));
    },
    fetchLoginStatus: (cognitoBaseURL) => {
      return dispatch(fetchLoginStatus(cognitoBaseURL));
    },
  };
})(SomeComponent));
2.1.0

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago

0.0.1

5 years ago