简体   繁体   English

React-Admin 简单刷新 JWT 令牌

[英]React-Admin Simple Refresh JWT Token

I have an react-admin with an auth provider like the below.我有一个带有如下身份验证提供程序的 react-admin。 I want to refresh my token, but I don't know how to do it.我想刷新我的令牌,但我不知道该怎么做。 I tried to follow this blog post , but my auth is a little different and I can't make it work (the error "httpClient(...).then" is not a function and others make me leave it).我尝试关注这篇文,但我的身份验证有点不同,我无法让它工作(错误“httpClient(...).then”不是 function 和其他人让我离开它)。

I can make it with a more simple solution, does not need to be in memory.我可以用更简单的解决方案来制作它,不需要在 memory 中。 I tried to call my refresh endpoint to get my refresh token, but my call go without the current token.我试图调用我的刷新端点来获取我的刷新令牌,但我的调用 go 没有当前令牌。

My endpoint to refresh the token is: /auth/jwt/refresh我刷新令牌的端点是:/auth/jwt/refresh

I need to call it like this:我需要这样称呼它:

curl -X 'GET' \
  'http://localhost:8000/auth/jwt/refresh' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

And My response body would be: (and I need to save it to my localstorage or the in memory way)我的响应正文将是:(我需要将其保存到我的本地存储或 memory 方式)

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTUwZDdhZDctOWE5Ni00NzQyLTgxNWEtZTNmZmJmNGRiMTVjIiwiYXVkIjpbImZhc3RhcGktdXNlcnM6YXV0aCJdLCJleHAiOjE2Mzk4NDE1MDF9.-o2yk56sCj_MZx_VA6PxH7gZ-KKSMmopbDNDiapHmn0",
  "token_type": "bearer"
}

My inMemoryJWTManager file:我的 inMemoryJWTManager 文件:

const inMemoryJWTManager = () => {
    let inMemoryJWT = null;
    let isRefreshing = null;
    let logoutEventName = 'ra-logout';
    let refreshEndpoint = '/auth/jwt/refresh';
    let refreshTimeOutId;

    const setLogoutEventName = name => logoutEventName = name;
    const setRefreshTokenEndpoint = endpoint => refreshEndpoint = endpoint;

    // This countdown feature is used to renew the JWT before it's no longer valid
    // in a way that is transparent to the user.
    const refreshToken = (delay) => {
        refreshTimeOutId = window.setTimeout(
            getRefreshedToken,
            delay * 1000 - 5000
        ); // Validity period of the token in seconds, minus 5 seconds
    };

    const abordRefreshToken = () => {
        if (refreshTimeOutId) {
            window.clearTimeout(refreshTimeOutId);
        }
    };

    const waitForTokenRefresh = () => {
        if (!isRefreshing) {
            return Promise.resolve();
        }
        return isRefreshing.then(() => {
            isRefreshing = null;
            return true;
        });
    }

    // The method make a call to the refresh-token endpoint
    // If there is a valid cookie, the endpoint will set a fresh jwt in memory.
    const getRefreshedToken = () => {
        const request = new Request(refreshEndpoint, {
            method: 'GET',
            headers: new Headers({ 'Content-Type': 'application/json' }),
            credentials: 'include',
        });

        isRefreshing = fetch(request)
            .then((response) => {
                if (response.status !== 200) {
                    ereaseToken();
                    global.console.log(
                        'Token renewal failure'
                    );
                    return { token: null };
                }
                return response.json();
            })
            .then(({ token, tokenExpiry }) => {
                if (token) {
                    setToken(token, tokenExpiry);
                    return true;
                }
                ereaseToken();
                return false;
            });

        return isRefreshing;
    };


    const getToken = () => inMemoryJWT;

    const setToken = (token, delay) => {
        inMemoryJWT = token;
        refreshToken(delay);
        return true;
    };

    const ereaseToken = () => {
        inMemoryJWT = null;
        abordRefreshToken();
        window.localStorage.setItem(logoutEventName, Date.now());
        return true;
    }

    // This listener will allow to disconnect a session of ra started in another tab
    window.addEventListener('storage', (event) => {
        if (event.key === logoutEventName) {
            inMemoryJWT = null;
        }
    });

    return {
        ereaseToken,
        getRefreshedToken,
        getToken,
        setLogoutEventName,
        setRefreshTokenEndpoint,
        setToken,
        waitForTokenRefresh,
    }
};

export default inMemoryJWTManager();

This is my auth provider: (updated, using inMemoryJWTManager)这是我的身份验证提供程序:(已更新,使用 inMemoryJWTManager)

import inMemoryJWTManager from './inMemoryJWT'
const apiUrl = 'http://localhost:8000'

const authProvider = {
    login: ({username, password}) => {

        const oAuthParams = {
            username,
            password
        }
        const body = Object.keys(oAuthParams).map((key) => {
            return encodeURIComponent(key) + '=' + encodeURIComponent(oAuthParams[key]);
          }).join('&');

        const request = new Request(`${apiUrl}/auth/jwt/login`, {
            method: 'POST',
            body: body,
            headers: new Headers({'Content-Type': 'application/x-www-form-urlencoded'}),
        }); 
        return fetch(request)
            .then(response => {
                if (response.status < 200 || response.status >= 300) {
                    throw new Error(response.statusText);
                }
                return response.json();
            })
            .then(( {access_token} ) => {
                inMemoryJWTManager.setToken(access_token);
            }); 
    },
    checkError: (error) => {
        const status = error.status;
        if (status === 401 || status === 403) {
            inMemoryJWTManager.ereaseToken();
            return Promise.reject({redirectTo: '/login'});
        }
        // other error code (404, 500, etc): no need to log out
        return Promise.resolve();
    },
    checkAuth: () => inMemoryJWTManager.getToken()
    ? Promise.resolve()
    : Promise.reject({ message: 'Login necessário', redirectTo: 'login' }),

    logout: () => {
        inMemoryJWTManager.ereaseToken();
        return Promise.resolve();
    },

    getPermissions: () => {
        return inMemoryJWTManager.getToken() ? Promise.resolve() : Promise.reject();
    },
};

export default authProvider;

My updated httpClient code using inMemoryJWTManager: (and I'm using: const dataProvider = jsonServerProvider(apiUrl, httpClient); with modifications to it, but I think it is irrelevant)我使用 inMemoryJWTManager 更新的 httpClient 代码:(我正在使用: const dataProvider = jsonServerProvider(apiUrl, httpClient);进行了修改,但我认为这无关紧要)

const httpClient = (url) => {
    const options = {
        headers: new Headers({ Accept: 'application/json' }),
    };
    const token = inMemoryJWTManager.getToken();
    console.log(token)

    if (token) {
        options.headers.set('Authorization', `Bearer ${token}`);
        return fetchUtils.fetchJson(url, options);
    } else {
        inMemoryJWTManager.setRefreshTokenEndpoint(`${apiUrl}/auth/jwt/refresh`);
        return inMemoryJWTManager.getRefreshedToken().then((gotFreshToken) => {
            if (gotFreshToken) {
                options.headers.set('Authorization', `Bearer ${inMemoryJWTManager.getToken()}`);
            };
            return fetchUtils.fetchJson(url, options);
        });
    }
};

My problem is that, when I call my refresh token endpoint, my request go without the {'Authorization': Bearer... and it is not renewed and I got logged out.我的问题是,当我调用刷新令牌端点时,我的请求 go 没有{'Authorization': Bearer...并且它没有更新并且我已注销。 The other endpoints are fine, they go with the token.其他端点都很好,它们是带有令牌的 go。

You must check token expire before each requests, if token expired you must get new from /auth/jwt/refresh , then you can send current request.您必须在每个请求之前检查令牌过期,如果令牌过期,您必须从/auth/jwt/refresh获取新的,然后您可以发送当前请求。 All this information is in the article post .所有这些信息都在文章中。 Example:例子:

const httpClient = (url) => {
    const options = {
        headers: new Headers({ Accept: 'application/json' }),
    };
    const token = inMemoryJWT.getToken();

    if (token) {
        options.headers.set('Authorization', `Bearer ${token}`);
        return fetchUtils.fetchJson(url, options);
    } else {
        inMemoryJWT.setRefreshTokenEndpoint('http://localhost:8001/refresh-token');
        return inMemoryJWT.getRefreshedToken().then((gotFreshToken) => {
            if (gotFreshToken) {
                options.headers.set('Authorization', `Bearer ${inMemoryJWT.getToken()}`);
            };
            return fetchUtils.fetchJson(url, options);
        });
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM