2016-06-28 25 views
6

Tôi có ứng dụng Redux và API từ xa phục vụ như một máy chủ OAuth. Dựa trên thói quen thông thường, người dùng trao đổi thông tin đăng nhập của họ với mã thông báo mà sau đó được ứng dụng sử dụng để tìm nạp dữ liệu và thực hiện một số nội dung trên máy chủ. Mã thông báo này được lưu trữ trong cửa hàng và cũng vào sessionStorage.Chiến lược để phân phối mã thông báo truy cập OAuth trong ứng dụng Redux

Bây giờ, đôi khi mã thông báo truy cập sẽ hết hạn, nhưng vì đã nhận được mã thông báo làm mới, nên cố làm mới trước và chỉ khi mã thông báo sai, hãy đăng xuất người dùng.

Tôi hoàn toàn hiểu phần đăng xuất, về mặt kỹ thuật có nghĩa là chỉ cần gửi một hành động nhất định. Nhưng làm thế nào tôi có thể đơn giản hóa thói quen làm mới mã thông báo?

Tôi đã thử sử dụng redux-saga nhưng nó rất dài dòng. Tôi theo nghĩa đen phải sao chép một phần mã cho mọi hành động phụ thuộc vào API từ xa, để đảm bảo mọi yêu cầu như vậy trước tiên sẽ kiểm tra mã thông báo truy cập và liệu nó chưa hết hạn và quản lý để làm mới nó theo cách khác.

Một điều khác mà tôi đã cố gắng làm là một phần mềm trung gian có thể mong đợi một loại hành động nhất định với yêu cầu API từ xa được gói vào Lời hứa. Loại tác phẩm này, nhưng tôi tò mò nếu có cách khác để làm.

Có ai từng thực hiện loại điều này (khá chung chung) không? Bất kỳ ý tưởng làm thế nào để tự động làm mới mã thông báo và không nổi giận với số lượng mã tăng lên? Có thể thành phần bậc cao hơn?

+1

Mặc dù có câu trả lời được đánh dấu là giải pháp, mọi người đều rất hoan nghênh để thêm suy nghĩ và kinh nghiệm của họ. –

Trả lời

9

Đối với mã cần phải xảy ra nhiều lần và cho một thứ cần phải liền mạch và chung chung, phần giữa thường là cách để đi. Nó có thể đơn giản như thêm hai dòng mã để bao gồm phần mềm trung gian khi tạo cửa hàng và viết lên một hàm đơn giản sẽ xử lý logic mã thông báo cho bạn.

Hãy nói rằng bạn sẽ tạo ra cửa hàng của bạn như vậy:

import { createStore, applyMiddleware, compose } from 'redux'; 
import rootReducer from './reducers'; 
import { browserHistory } from 'react-router'; 
import { routerMiddleware } from 'react-router-redux'; 
import tokenMiddleware from './middleware/token'; 

const finalCreateStore = compose(
    applyMiddleware(
     routerMiddleware(browserHistory), 
     tokenMiddleware, 
    ), 
    window.devToolsExtension ? window.devToolsExtension() : f => f, 
)(createStore); 

Sau đó, bạn sẽ gọi hàm này từ đâu đó, với tình trạng ban đầu.

const store = finalCreateStore(rootReducer, initialState); 

Điều này sẽ cho phép bạn làm điều gì đó với tất cả các hành động đi qua cửa hàng. Vì nó là rất phổ biến để có một middleware xử lý các cuộc gọi API bằng cách sử dụng lời hứa, một số người thích tái sử dụng cho mục đích này là tốt và bó hai lại với nhau.

Một middleware điển hình sẽ giống như thế này:

export const tokenMiddleware = ({ dispatch, getState }) => next => action => { 
    if (typeof action === 'function') { // pass along 
     return action(dispatch, getState); 
    } 

    // so let's say you have a token that's about to expire 
    // and you would like to refresh it, let's write so pseudo code 

    const currentState = getState(); 
    const userObj = state.authentication.user; 

    if (userObj.token && userObj.token.aboutToExpire) { 
     const config = getSomeConfigs(); 
     // some date calculation based on expiry time that we set in configs 
     const now = new Date(); 
     const refreshThreshold = config.token.refreshThreshold; 

     if (aboutToExpireAndIsBelowThresholdToRefresh) { 
      // refreshTheToken can be an action creator 
      // from your auth module for example 
      // it should probably be a thunk so that you can handle 
      // an api call and a promise within once you get the new token 
      next(refreshTheToken(userObj, someOtherParams); 
     } 
    } 

    .... 

    return next(action); 
} 

refresh của bạn thunk dấu hiệu có thể là một cái gì đó tương tự như sau:

function refreshToken(user, maybeSomeOtherParams) { 
    const config = getSomeConfigs; 

    return dispatch => { 
     makeAPostCallWithParamsThatReturnsPromise 
     .then(result => dispatch(saveNewToken({ 
      result, 
      ... 
     }))) 
     .catch(error => dispatch({ 
      type: uh_oh_token_refresh_failed_action_type, 
      error, 
     })); 
}; 

Một thay thế mà bạn có thể có thể đi cho sẽ được xử lý điều này khi thay đổi tuyến đường.

Giả sử bạn sẽ có tuyến đường cấp cao nhất ở đâu đó cho các tuyến đường cần xác thực và người dùng hợp lệ có mặt trong hệ thống. Hãy gọi cho họ authenticated routes.

Bạn có thể quấn các authenticated routes này bằng tuyến đường cấp cao nhất, xác định hàm xử lý onChange.Một cái gì đó như thế này:

<Route onChange={authEntry}> 
    <Route ... /> // authenticated routes 
    <Route ... /> 
</Route> 

Khi tạo các đường bay và thành lập cửa hàng của bạn, một khi bạn đã tạo ra các cửa hàng, bạn có thể gắn nó vào chức năng này được gọi là checkAuth.

const authEntry = checkAuth.bind(null, store) 

Một cách khác sẽ được quấn các định nghĩa đường trong một chức năng và thông qua các cửa hàng vào nó, và sau đó bạn sẽ có quyền truy cập chỉ giống nhau, nhưng tôi thấy rằng là không sạch sẽ như thế này (sở thích cá nhân).

Bây giờ, điều này checkAuth sẽ làm gì?

Something như thế này:

export function checkAuth (store, previous, next, replace, callback) { 
    const currentUser = store.getState().auth.user 

    // can possibly dispatch actions from here too 
    // store.dispatch(..).then(() => callback()).. 
    // so you could possibly refresh the token here using an API call 
    // if it is about to expire 

    // you can also check if the token did actually expire and/or 
    // there's no logged in user trying to access the route, so you can redirect 

    if (!currentUser || !isLoggedIn(currentUser)) { 
     replace('/yourLoginRouteHere') 
    } 

    callback() // pass it along 
} 

Cả hai nên chung đủ để họ cung cấp cho bạn tái sử dụng mã trong một địa điểm tập trung. Hy vọng bạn sẽ tìm thấy những hữu ích.

+0

làm cách nào để bạn làm cho phần mềm trung gian này không làm mới mã thông báo nếu có bất kỳ hành động nào khác được gửi đi? giả sử mọi thứ không liên quan đến mạng hoặc một số yêu cầu khác không yêu cầu mã thông báo ủy quyền –

Các vấn đề liên quan