Fix missing redirect after login (#1592)

Each unauthorized error was caught by the token expired handler, which has reset the whole query state and this leads sometimes to a missing redirect after login.
This commit is contained in:
Sebastian Sdorra
2021-03-16 16:13:43 +01:00
committed by GitHub
parent ce0e94098e
commit 9ef076fb2f
8 changed files with 98 additions and 19 deletions

View File

@@ -0,0 +1,2 @@
- type: fixed
description: Sometimes no redirect after login ([#1592](https://github.com/scm-manager/scm-manager/pull/1592))

View File

@@ -30,7 +30,7 @@
"gitdiff-parser": "^0.1.2",
"query-string": "5",
"react": "^17.0.1",
"react-query": "^3.5.16"
"react-query": "^3.12.2"
},
"babel": {
"presets": [

View File

@@ -23,7 +23,15 @@
*/
import { contextPath } from "./urls";
import { BackendErrorContent, createBackendError, ForbiddenError, isBackendError, UnauthorizedError } from "./errors";
import {
BackendErrorContent,
createBackendError,
ForbiddenError,
isBackendError,
TOKEN_EXPIRED_ERROR_CODE,
TokenExpiredError,
UnauthorizedError
} from "./errors";
type SubscriptionEvent = {
type: string;
@@ -119,6 +127,15 @@ const applyFetchOptions: (p: RequestInit) => RequestInit = o => {
function handleFailure(response: Response) {
if (!response.ok) {
if (response.status === 401) {
if (isBackendError(response)) {
return response.json().then((content: BackendErrorContent) => {
if (content.errorCode === TOKEN_EXPIRED_ERROR_CODE) {
throw new TokenExpiredError("Token expired", 401);
} else {
throw new UnauthorizedError("Unauthorized", 401);
}
});
}
throw new UnauthorizedError("Unauthorized", 401);
} else if (response.status === 403) {
throw new ForbiddenError("Forbidden", 403);

View File

@@ -72,14 +72,18 @@ export class BackendError extends Error {
export class UnauthorizedError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
}
export class TokenExpiredError extends UnauthorizedError {}
export class ForbiddenError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;

View File

@@ -23,7 +23,6 @@
*/
import { Me } from "@scm-manager/ui-types";
import { useEffect } from "react";
import { useMutation, useQuery } from "react-query";
import { apiClient } from "./apiclient";
import { ApiResult, useIndexLink } from "./base";
@@ -111,7 +110,7 @@ export const useLogout = () => {
if (response?.logoutRedirect) {
window.location.assign(response.logoutRedirect);
}
reset();
return reset();
}
}
);

View File

@@ -44,11 +44,18 @@ export const from = (queryString?: string, stateParams?: FromObject | null): str
return queryParams?.from || stateParams?.from || "/";
};
const Login: FC = ({}) => {
const Login: FC = () => {
const location = useLocation<FromObject>();
const { login, isLoading, error } = useLogin();
const loginInfoLink = useIndexLink("loginInfo");
// sometimes after logout the url is still /logout
// but it does not make sense to redirect to /logout
// directly after login
if (location.pathname === "/logout") {
return <Redirect to="/" />;
}
if (!login) {
const to = from(window.location.search, location.state);
return <Redirect to={to} />;

View File

@@ -23,17 +23,16 @@
*
*/
import { apiClient, clearCache, UnauthorizedError } from "@scm-manager/ui-api";
import { apiClient, clearCache, TokenExpiredError } from "@scm-manager/ui-api";
let tokenExpired = false;
// We assume that an UnauthorizedError means that the access token is expired.
// If the token is expired we want to show an error with the login link.
// This error should be displayed with the state (e.g. navigation) of the previous logged in user.
// But if the user navigates away, we want to reset the state to an anonymous one.
apiClient.onError(error => {
if (error instanceof UnauthorizedError) {
if (error instanceof TokenExpiredError) {
tokenExpired = true;
}
});

View File

@@ -2636,6 +2636,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.6.2":
version "7.13.10"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.4", "@babel/template@^7.3.3", "@babel/template@^7.4.0":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
@@ -7202,6 +7209,11 @@ better-opn@^2.0.0:
dependencies:
open "^7.0.3"
big-integer@^1.6.16:
version "1.6.48"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -7327,6 +7339,19 @@ braces@^3.0.1, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
broadcast-channel@^3.4.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.5.3.tgz#c75c39d923ae8af6284a893bfdc8bd3996d2dd2d"
integrity sha512-OLOXfwReZa2AAAh9yOUyiALB3YxBe0QpThwwuyRHLgpl8bSznSDmV6Mz7LeBJg1VZsMcDcNMy7B53w12qHrIhQ==
dependencies:
"@babel/runtime" "^7.7.2"
detect-node "^2.0.4"
js-sha3 "0.8.0"
microseconds "0.2.0"
nano-time "1.0.0"
rimraf "3.0.2"
unload "2.2.0"
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -14225,6 +14250,11 @@ js-levenshtein@^1.1.3:
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
js-sha3@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
js-string-escape@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
@@ -15515,6 +15545,11 @@ micromatch@^4.0.2:
braces "^3.0.1"
picomatch "^2.0.5"
microseconds@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -15860,6 +15895,13 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nano-time@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=
dependencies:
big-integer "^1.6.16"
nanoid@^3.1.3:
version "3.1.20"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
@@ -18131,12 +18173,13 @@ react-popper@^2.2.4:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-query@^3.5.16:
version "3.5.16"
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.5.16.tgz#172771a8cdb83b85c353ac32f1e30bfca27893d7"
integrity sha512-zOJimWPC0o2h8fta0uMc+pmFIBgfVkfCvEAeUbrlsbA6m42CFPgyRBJt6kiYjsZ/WRuJl+WIaAh/P27oUXETNw==
react-query@^3.12.2:
version "3.12.2"
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.12.2.tgz#57ae8056ba0cb63c9755cd00dc4cda45b29f9bb6"
integrity sha512-Qq/Vy+sz4QscLPfcZMrMHfuZKbKr47tsttHgcqkOiZGhLjsnYkLGcsSnMdOSLBzhzziYhs1i3plLmF0VMZw2Ng==
dependencies:
"@babel/runtime" "^7.5.5"
broadcast-channel "^3.4.1"
match-sorter "^6.0.2"
react-redux@^5.0.7:
@@ -18918,6 +18961,13 @@ rimraf@2.6.3:
dependencies:
glob "^7.1.3"
rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -18925,13 +18975,6 @@ rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
dependencies:
glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -20997,6 +21040,14 @@ universalify@^1.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
unload@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
dependencies:
"@babel/runtime" "^7.6.2"
detect-node "^2.0.4"
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"