@ssoeasy-dev/react 1.0.0-beta.64cfe3a → 1.0.0-beta.97c4d20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -0
- package/dist/ProtectedRoute.d.ts +1 -0
- package/dist/ProtectedRoute.d.ts.map +1 -1
- package/dist/ProtectedRoute.js +4 -1
- package/dist/ProtectedRoute.js.map +1 -1
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# @ssoeasy-dev/react
|
|
2
|
+
|
|
3
|
+
React-адаптер для SSO Easy. Оборачивает `@ssoeasy-dev/core` в React Context и предоставляет хук `useAuth` и компонент `ProtectedRoute`.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ssoeasy-dev/react @ssoeasy-dev/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Быстрый старт
|
|
12
|
+
|
|
13
|
+
### 1. Оборачиваем приложение в `AuthProvider`
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { AuthProvider } from "@ssoeasy-dev/react";
|
|
17
|
+
import { AuthManager } from "@ssoeasy-dev/core";
|
|
18
|
+
|
|
19
|
+
const auth = new AuthManager({
|
|
20
|
+
serviceId: "your-service-id",
|
|
21
|
+
redirectUri: "https://yourapp.com",
|
|
22
|
+
loginPath: "/callback",
|
|
23
|
+
authPageUrl: "https://sso.example.com/login",
|
|
24
|
+
authServerConfig: {
|
|
25
|
+
baseURL: "https://api.example.com",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<AuthProvider auth={auth}>
|
|
32
|
+
<AppRouter />
|
|
33
|
+
</AuthProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Защищаем роуты через `ProtectedRoute`
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
|
42
|
+
import { ProtectedRoute } from "@ssoeasy-dev/react";
|
|
43
|
+
|
|
44
|
+
function AppRouter() {
|
|
45
|
+
return (
|
|
46
|
+
<BrowserRouter>
|
|
47
|
+
<Routes>
|
|
48
|
+
<Route path="/callback" element={<CallbackPage />} />
|
|
49
|
+
<Route path="/" element={<PublicPage />} />
|
|
50
|
+
<Route
|
|
51
|
+
path="/dashboard"
|
|
52
|
+
element={
|
|
53
|
+
<ProtectedRoute redirectTo="/dashboard">
|
|
54
|
+
<Dashboard />
|
|
55
|
+
</ProtectedRoute>
|
|
56
|
+
}
|
|
57
|
+
/>
|
|
58
|
+
</Routes>
|
|
59
|
+
</BrowserRouter>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Используем `useAuth` в компонентах
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useAuth } from "@ssoeasy-dev/react";
|
|
68
|
+
|
|
69
|
+
function Header() {
|
|
70
|
+
const auth = useAuth();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<header>
|
|
74
|
+
{auth.getState().isAuthenticated ? (
|
|
75
|
+
<button onClick={() => auth.logout()}>Выйти</button>
|
|
76
|
+
) : (
|
|
77
|
+
<button onClick={() => auth.login()}>Войти</button>
|
|
78
|
+
)}
|
|
79
|
+
</header>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Страница callback
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { useEffect } from "react";
|
|
88
|
+
import { useAuth } from "@ssoeasy-dev/react";
|
|
89
|
+
import { useNavigate } from "react-router-dom";
|
|
90
|
+
|
|
91
|
+
function CallbackPage() {
|
|
92
|
+
const auth = useAuth();
|
|
93
|
+
const navigate = useNavigate();
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
auth.handleRedirectCallback().then(({ redirectTo }) => {
|
|
97
|
+
navigate(redirectTo, { replace: true });
|
|
98
|
+
});
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
return <div>Авторизация...</div>;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## API
|
|
106
|
+
|
|
107
|
+
### `AuthProvider`
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<AuthProvider auth={AuthManager}>{children}</AuthProvider>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Предоставляет `AuthManager` через React Context. Должен оборачивать всё приложение.
|
|
114
|
+
|
|
115
|
+
### `useAuth`
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
const auth = useAuth(); // возвращает AuthManager
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Хук для доступа к `AuthManager` внутри компонентов. Выбрасывает ошибку если вызван вне `AuthProvider`.
|
|
122
|
+
|
|
123
|
+
### `ProtectedRoute`
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
<ProtectedRoute
|
|
127
|
+
redirectTo="/target-path" // путь для redirectTo при логине (опционально)
|
|
128
|
+
fallback={<Spinner />} // отображается во время checkAuth (по умолчанию <div>Loading...</div>)
|
|
129
|
+
unauthenticatedElement={<Node />} // рендерится вместо редиректа на SSO, если пользователь не авторизован (опционально)
|
|
130
|
+
>
|
|
131
|
+
<ProtectedContent />
|
|
132
|
+
</ProtectedRoute>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
При монтировании вызывает `auth.checkAuth()`. Пока идёт проверка — рендерит `fallback`.
|
|
136
|
+
|
|
137
|
+
Если пользователь не авторизован:
|
|
138
|
+
|
|
139
|
+
- **`unauthenticatedElement` не передан** — вызывает `auth.login({ redirectTo })`, редирект на SSO (поведение по умолчанию)
|
|
140
|
+
- **`unauthenticatedElement` передан** — рендерит переданный элемент без редиректа
|
|
141
|
+
|
|
142
|
+
#### Пример: внутренняя страница выбора входа/регистрации
|
|
143
|
+
|
|
144
|
+
Если в приложении есть собственная страница `/auth` с кнопками «Войти» и «Зарегистрироваться», можно передать `<Navigate>` вместо того, чтобы сразу уходить на SSO:
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { Navigate } from "react-router-dom";
|
|
148
|
+
import { ProtectedRoute } from "@ssoeasy-dev/react";
|
|
149
|
+
|
|
150
|
+
const LayoutWrapper = () => {
|
|
151
|
+
return (
|
|
152
|
+
<ProtectedRoute unauthenticatedElement={<Navigate to="/auth" replace />}>
|
|
153
|
+
<Layout>
|
|
154
|
+
<Outlet />
|
|
155
|
+
</Layout>
|
|
156
|
+
</ProtectedRoute>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Страница `/auth` при этом остаётся публичной — она не обёрнута в `ProtectedRoute`.
|
|
162
|
+
|
|
163
|
+
## Экспорты
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
export { AuthProvider } from "./AuthProvider";
|
|
167
|
+
export { ProtectedRoute } from "./ProtectedRoute";
|
|
168
|
+
export { useAuth } from "./useAuth";
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Лицензия
|
|
172
|
+
|
|
173
|
+
MIT — см. [LICENSE](../LICENSE).
|
|
174
|
+
|
|
175
|
+
## Контакты
|
|
176
|
+
|
|
177
|
+
- Email: morewiktor@yandex.ru
|
|
178
|
+
- Telegram: [@MoreWiktor](https://t.me/MoreWiktor)
|
|
179
|
+
- GitHub: [@MoreWiktor](https://github.com/MoreWiktor)
|
package/dist/ProtectedRoute.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProtectedRoute.d.ts","sourceRoot":"","sources":["../src/ProtectedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ProtectedRoute.d.ts","sourceRoot":"","sources":["../src/ProtectedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,sBAAsB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1C,CA0BA,CAAC"}
|
package/dist/ProtectedRoute.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
import { useAuth } from "./useAuth";
|
|
4
|
-
export const ProtectedRoute = ({ children, redirectTo, fallback = _jsx("div", { children: "Loading..." }) }) => {
|
|
4
|
+
export const ProtectedRoute = ({ children, redirectTo, fallback = _jsx("div", { children: "Loading..." }), unauthenticatedElement, }) => {
|
|
5
5
|
const auth = useAuth();
|
|
6
6
|
const [isAuthorized, setIsAuthorized] = useState(null);
|
|
7
7
|
useEffect(() => {
|
|
@@ -12,6 +12,9 @@ export const ProtectedRoute = ({ children, redirectTo, fallback = _jsx("div", {
|
|
|
12
12
|
if (isAuthorized === null)
|
|
13
13
|
return fallback;
|
|
14
14
|
if (!isAuthorized) {
|
|
15
|
+
if (unauthenticatedElement !== undefined) {
|
|
16
|
+
return _jsx(_Fragment, { children: unauthenticatedElement });
|
|
17
|
+
}
|
|
15
18
|
auth.login({ redirectTo });
|
|
16
19
|
return null;
|
|
17
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProtectedRoute.js","sourceRoot":"","sources":["../src/ProtectedRoute.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"ProtectedRoute.js","sourceRoot":"","sources":["../src/ProtectedRoute.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,cAAc,GAKtB,CAAC,EACJ,QAAQ,EACR,UAAU,EACV,QAAQ,GAAG,uCAAqB,EAChC,sBAAsB,GACvB,EAAE,EAAE;IACH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAiB,IAAI,CAAC,CAAC;IAEvE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YAC5B,eAAe,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC;IAE3C,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,IAAI,sBAAsB,KAAK,SAAS,EAAE,CAAC;YACzC,OAAO,4BAAG,sBAAsB,GAAI,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,4BAAG,QAAQ,GAAI,CAAC;AACzB,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ssoeasy-dev/react",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.97c4d20",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"types": "index.ts",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"README.md",
|
|
16
16
|
"LICENSE"
|
|
17
17
|
],
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
20
|
+
"@ssoeasy-dev/core": "1.0.0-beta.2bdd988"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/react": "^19.2.14",
|