diff --git a/.github/workflows/docs.links.check.config.json b/.github/workflows/docs.links.check.config.json index 233c8d3aa..1074930d6 100644 --- a/.github/workflows/docs.links.check.config.json +++ b/.github/workflows/docs.links.check.config.json @@ -50,6 +50,15 @@ }, { "pattern": "^https://stackoverflow.com/" + }, + { + "pattern": "^https://www.jumio.com/" + }, + { + "pattern": "^https://gitee.com/oauth/" + }, + { + "pattern": "^https://gitlab.com/-/profile/" } ] } diff --git a/docs/basic/public-api.md b/docs/basic/public-api.md index 56f139207..5b9b5714f 100644 --- a/docs/basic/public-api.md +++ b/docs/basic/public-api.md @@ -189,9 +189,9 @@ Create a key pair on the user’s account settings page. **Query parameters:** - ```shell - /page?accessKey=&accessSecret=" - ``` +```shell +/page?accessKey=&accessSecret=" +``` Example: `https://door.casdoor.com/api/get-global-providers?accessKey=...&accessSecret=...` @@ -211,9 +211,9 @@ Username format: `/`. API calls run as that user. **Query parameters:** - ```shell - /page?username=/&password=" - ``` +```shell +/page?username=/&password=" +``` ## SSO logout diff --git a/docs/basic/server-installation.mdx b/docs/basic/server-installation.mdx index 7e3894058..b7b048d5f 100644 --- a/docs/basic/server-installation.mdx +++ b/docs/basic/server-installation.mdx @@ -193,8 +193,9 @@ To use a different port, set `httpport` in `conf/app.conf` and restart the backe ::: :::info Ports and URLs -- **Dev:** Frontend runs on port 7001 (`yarn start`). Point apps at **http://localhost:7001** for the Casdoor login page. -- **Prod:** Frontend is built and served by the backend on port 8000. Use **https://your-casdoor-domain** (or your reverse proxy URL). + +- **Dev:** Frontend runs on port 7001 (`yarn start`). Point apps at `http://localhost:7001` for the Casdoor login page. +- **Prod:** Frontend is built and served by the backend on port 8000. Use `https://your-casdoor-domain` (or your reverse proxy URL). ::: **Example:** [Casnode](https://casnode.org) uses Casdoor. In dev, set `serverUrl` to `http://localhost:7001`; in prod, set it to `https://door.casdoor.com`. diff --git a/docs/how-to-connect/mobile-sdks/react-native-app.md b/docs/how-to-connect/mobile-sdks/react-native-app.md index 4172ed23b..b64babee3 100644 --- a/docs/how-to-connect/mobile-sdks/react-native-app.md +++ b/docs/how-to-connect/mobile-sdks/react-native-app.md @@ -41,7 +41,6 @@ After sign-in, the user profile is shown. |:-------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------:| | iOS-userInfo | Android-userInfo | - | **iOS** | **Android** | |:--------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------:| | iOS-gif | Android-gif | diff --git a/docs/how-to-connect/oauth.md b/docs/how-to-connect/oauth.md index ee88f9e86..82cd63b6f 100644 --- a/docs/how-to-connect/oauth.md +++ b/docs/how-to-connect/oauth.md @@ -13,7 +13,7 @@ Authorization code is enabled by default for security. Enable other grant types ![Grant Types](/img/how-to-connect/oauth/accesstoken_grant_types.png) -### Authorization code grant +### Authorization code grant Redirect the user to: diff --git a/docs/how-to-connect/saml/tencent-cloud.md b/docs/how-to-connect/saml/tencent-cloud.md index 1c914e78b..0402e4059 100644 --- a/docs/how-to-connect/saml/tencent-cloud.md +++ b/docs/how-to-connect/saml/tencent-cloud.md @@ -40,6 +40,7 @@ This guide configures Casdoor as a SAML identity provider for **Tencent Cloud** :::info Replace placeholders using: + - **{'{'}AccountID{'}'}**: Tencent Cloud account ID — [Account Information](https://console.cloud.tencent.com/developer) - **{'{'}RoleName{'}'}**: Role name — [Roles](https://console.cloud.tencent.com/cam/role) - **{'{'}ProviderName{'}'}**: SAML identity provider name — [Identity Providers](https://console.cloud.tencent.com/cam/idp) diff --git a/docs/integration/python/casbin-fastapi.md b/docs/integration/python/casbin-fastapi.md new file mode 100644 index 000000000..80d91220a --- /dev/null +++ b/docs/integration/python/casbin-fastapi.md @@ -0,0 +1,191 @@ +--- +title: FastAPI +description: Using Casdoor OAuth2 authentication and Casbin authorization in a FastAPI project via casbin-fastapi-decorator. +keywords: [FastAPI, Casbin, Python, authorization, OAuth2] +authors: [Neko1313] +--- + +[casbin-fastapi-decorator](https://github.com/Neko1313/casbin-fastapi-decorator) is a community library that provides decorator-based Casbin authorization for FastAPI. Its **Casdoor extra** (`casbin-fastapi-decorator-casdoor`) combines Casdoor OAuth2 login with Casbin policy enforcement through Casdoor's remote enforce API, while keeping route signatures clean and dependency-injection free. + +## Step 1: Deploy Casdoor + +Deploy Casdoor in **production mode**. See [Server installation](/docs/basic/server-installation). Make sure the server is reachable and you can sign in (e.g. `admin` / `123`). + +## Step 2: Configure a Casdoor application + +In the Casdoor admin panel, create or open an application and configure: + +- **Redirect URL** — add your FastAPI callback URL, e.g. `http://localhost:8080/callback` +- Copy the **Client ID**, **Client Secret**, and **Certificate** + +You will also need either an **Enforcer**, **Permission**, or **Model** identifier to pass as the enforce target. + +The application should start sign-in at `GET /login`; Casdoor itself should redirect back only to `GET /callback`. + +## Step 3: Install the library + +```bash +pip install "casbin-fastapi-decorator[casdoor]>=0.2.3" +``` + +Requires Python ≥ 3.10. + +:::info Version guidance +Use `casbin-fastapi-decorator` `0.2.3` or newer in production. Versions `0.2.2` and earlier accepted the OAuth2 `state` parameter on the callback but did not validate it, which left the login flow without CSRF protection. Version `0.2.3` adds a dedicated `GET /login` entry point, default `CookieStateManager`, and callback `state` verification. +::: + +## Step 4: Quick start with `CasdoorIntegration` + +`CasdoorIntegration` is a facade that wires together the Casdoor SDK, user provider, enforcer provider, and OAuth2 router in a single call. + +```python +from casbin_fastapi_decorator_casdoor import ( + CasdoorEnforceTarget, + CasdoorIntegration, +) +from fastapi import FastAPI + +app = FastAPI() + +casdoor = CasdoorIntegration( + endpoint="http://localhost:8000", + client_id="", + client_secret="", + certificate="-----BEGIN CERTIFICATE-----\n...", + org_name="built-in", + application_name="app-built-in", + target=CasdoorEnforceTarget( + enforce_id=lambda parsed: f"{parsed['owner']}/my-enforcer" + ), +) + +# Register GET /login, GET /callback and POST /logout routes +app.include_router(casdoor.router) + +# Create a pre-configured PermissionGuard +guard = casdoor.create_guard() + +@app.get("/protected") +@guard.require_permission("resource", "read") +async def protected(): + return {"ok": True} + +@app.get("/me") +@guard.auth_required() +async def me(): + return {"ok": True} +``` + +Start the browser flow at `GET /login`. The router issues a one-time OAuth2 `state`, redirects to Casdoor, validates that `state` on the callback, exchanges the authorization code for tokens, and finally stores `access_token` and `refresh_token` cookies. + +:::tip Custom state storage +`0.2.3` uses `CookieStateManager` by default, which is sufficient for most deployments. If you need server-side or shared state storage, pass a custom `state_manager` implementing `CasdoorStateManager`. + +```python +from casbin_fastapi_decorator_casdoor import ( + CasdoorStateManager, + CookieStateManager, + make_casdoor_router, +) + +state_manager: CasdoorStateManager = CookieStateManager( + cookie_name="casdoor_oauth_state", + cookie_secure=True, +) + +# assuming existing_sdk = AsyncCasdoorSDK(...) +router = make_casdoor_router( + sdk=existing_sdk, + state_manager=state_manager, +) +``` + +If you are upgrading from `0.2.2` or earlier, update your sign-in links to point at `/login` instead of constructing the Casdoor authorization URL manually. +::: + +## Step 5: Choose an enforce target + +`CasdoorEnforceTarget` controls which Casdoor API identifier is used for policy checks. Fields accept static strings or callables that receive the parsed JWT payload: + +| Field | Casdoor API parameter | +|---|---| +| `enforce_id` | Enforcer ID | +| `permission_id` | Permission ID | +| `model_id` | Model ID | +| `resource_id` | Resource ID | +| `owner` | Organization owner | + +```python +# Dynamic — organisation taken from the user's JWT +CasdoorEnforceTarget(enforce_id=lambda parsed: f"{parsed['owner']}/my-enforcer") + +# Static +CasdoorEnforceTarget(permission_id="built-in/can-read-articles") +``` + +## Advanced usage (manual composition) + +For cases requiring a custom user factory, per-route enforce targets, custom `state` storage, or custom error handling, the components can be composed directly: + +```python +from casdoor import AsyncCasdoorSDK +from fastapi import FastAPI, HTTPException +from casbin_fastapi_decorator import PermissionGuard +from casbin_fastapi_decorator_casdoor import ( + CasdoorEnforceTarget, + CasdoorEnforcerProvider, + CasdoorUserProvider, + CookieStateManager, + make_casdoor_router, +) + +sdk = AsyncCasdoorSDK( + endpoint="http://localhost:8000", + client_id="", + client_secret="", + certificate="", + org_name="built-in", + application_name="app-built-in", +) + +target = CasdoorEnforceTarget(permission_id="built-in/can-read") +user_provider = CasdoorUserProvider(sdk=sdk) +enforcer_provider = CasdoorEnforcerProvider(sdk=sdk, target=target) +router = make_casdoor_router( + sdk=sdk, + state_manager=CookieStateManager(cookie_secure=True), + redirect_after_login="/dashboard", +) + +guard = PermissionGuard( + user_provider=user_provider, + enforcer_provider=enforcer_provider, + error_factory=lambda user, *rv: HTTPException(403, "Forbidden"), +) + +app = FastAPI() +app.include_router(router) + +@app.get("/articles") +@guard.require_permission("articles", "read") +async def list_articles(): + return [] +``` + +## Components overview + +| Component | Description | +|---|---| +| `CasdoorUserProvider` | Validates `access_token` and `refresh_token` cookies via the Casdoor SDK (JWT verification) | +| `CasdoorEnforcerProvider` | Delegates policy checks to Casdoor's remote enforce API (`/api/enforce`) | +| `CasdoorEnforceTarget` | Selects which Casdoor API identifier to use; values can be static or callables receiving the parsed JWT | +| `CookieStateManager` | Default one-time OAuth2 `state` storage and verification using an HttpOnly cookie | +| `CasdoorIntegration` | Facade combining all of the above with configurable cookie, redirect, and `state` settings | +| `make_casdoor_router` | Creates an `APIRouter` with `GET /login`, `GET /callback`, and `POST /logout` | + +## More resources + +- [casbin-fastapi-decorator on GitHub](https://github.com/Neko1313/casbin-fastapi-decorator) +- [casbin-fastapi-decorator on PyPI](https://pypi.org/project/casbin-fastapi-decorator/) +- [casbin-fastapi-decorator-casdoor on PyPI](https://pypi.org/project/casbin-fastapi-decorator-casdoor/) +- [casbin-fastapi-decorator changelog](https://github.com/Neko1313/casbin-fastapi-decorator/blob/main/CHANGELOG.md) diff --git a/docs/provider/idv/jumio.md b/docs/provider/idv/jumio.md index 5b012c987..babc8ad1c 100644 --- a/docs/provider/idv/jumio.md +++ b/docs/provider/idv/jumio.md @@ -26,6 +26,7 @@ In the Jumio dashboard, open the API credentials section. Note your **API Token* ### 2. Create the provider in Casdoor **Providers** → **Add**. Set **Category** to **ID Verification**, **Type** to **Jumio**, and fill in: + - **Client ID** — Jumio API Token - **Client Secret** — Jumio API Secret - **Endpoint** — Jumio API URL diff --git a/docs/provider/oauth/azureAD.md b/docs/provider/oauth/azureAD.md index 5604d5e90..18f517366 100644 --- a/docs/provider/oauth/azureAD.md +++ b/docs/provider/oauth/azureAD.md @@ -5,6 +5,8 @@ keywords: [Azure AD, Azure, OAuth] authors: [leo220yuyaodog] --- + + **Azure Active Directory (Azure AD)** provides a single identity for cloud and on-premises apps. Use it as an OAuth provider in Casdoor so users can sign in with their Microsoft accounts. ## Register an application diff --git a/docs/provider/oauth/baidu.md b/docs/provider/oauth/baidu.md index 5d78d2a04..32ec9c6af 100644 --- a/docs/provider/oauth/baidu.md +++ b/docs/provider/oauth/baidu.md @@ -5,6 +5,8 @@ keywords: [Baidu, Baidu OAuth] authors: [Steve0x2a] --- + + 1. Read [Baidu Open Auth](https://openauth.baidu.com/doc/regdevelopers.html?qq-pf-to=pcqq.c2c) and [create an application](http://developer.baidu.com/console#app/create). ![Create Baidu APP](/img/providers/OAuth/baiduapp.png) @@ -15,6 +17,7 @@ authors: [Steve0x2a] ![Redirect URL Setting](/img/providers/OAuth/baidudomain.png) :::caution + - Use the **domain** setting for your Casdoor domain; adding the full callback URL in the callback URL field often fails validation and breaks login. - Only one URL or domain can be added. ::: @@ -28,6 +31,7 @@ authors: [Steve0x2a] ![Baidu Provider](/img/providers/OAuth/baiduprovider.png) :::info Troubleshooting + - If Baidu reports an incorrect redirect URL: add your domain in the correct place, then reset the Secret (Baidu may show an error but the secret updates after refresh). If it still fails, delete the app and create a new one, and set the domain first. - Baidu returns a masked username; Casdoor uses that masked value as the username. ::: diff --git a/docs/provider/oauth/gitee.md b/docs/provider/oauth/gitee.md index 9a1062fa9..f3a9fdef2 100644 --- a/docs/provider/oauth/gitee.md +++ b/docs/provider/oauth/gitee.md @@ -5,6 +5,8 @@ keywords: [Gitee, OAuth] authors: [ErikQQY] --- + + 1. Go to [Gitee OAuth applications](https://gitee.com/oauth/applications) and create an application (or open an existing one). ![Gitee Workbench](/img/providers/OAuth/giteebench.png) diff --git a/docs/provider/oauth/github.md b/docs/provider/oauth/github.md index de5a5ec42..63e0f3f39 100644 --- a/docs/provider/oauth/github.md +++ b/docs/provider/oauth/github.md @@ -9,6 +9,8 @@ GitHub OAuth supports both the web application flow and the device flow. Use a * ## Register a GitHub App + + 1. Go to [GitHub Developer Settings](https://github.com/settings/apps/new) and create a new **GitHub App**. 2. Set **GitHub App name**, **Homepage URL**, **Description**, and **Callback URL**. diff --git a/docs/provider/oauth/gitlab.md b/docs/provider/oauth/gitlab.md index b92b980c7..591d2b7e6 100644 --- a/docs/provider/oauth/gitlab.md +++ b/docs/provider/oauth/gitlab.md @@ -9,6 +9,8 @@ Use the [GitLab Applications](https://gitlab.com/-/profile/applications) page (o ## Create the GitLab application + + 1. Click **Add new application**. 2. Set **Name** (e.g. "Casdoor"), **Redirect URI**, and **Scopes**. diff --git a/docs/provider/oauth/google.md b/docs/provider/oauth/google.md index 99d29a5ed..6a1cb8723 100644 --- a/docs/provider/oauth/google.md +++ b/docs/provider/oauth/google.md @@ -9,6 +9,8 @@ Configure Google OAuth in the [Google API Console](https://console.developers.go ## Configure in Google Cloud + + 1. Create or select a project. Open **APIs & Services** → **OAuth consent screen** and configure the consent screen. 2. Go to **Credentials** → **Create credentials** → **OAuth client ID**. Choose application type (e.g. Web application) and set **Authorized redirect URIs**. diff --git a/docs/provider/oauth/infoflow.md b/docs/provider/oauth/infoflow.md index 39288fa25..ce763cdfb 100644 --- a/docs/provider/oauth/infoflow.md +++ b/docs/provider/oauth/infoflow.md @@ -5,6 +5,8 @@ keywords: [Infoflow, OAuth, Baidu] authors: [Steve0x2a] --- + + 1. Log in at [Infoflow](http://id.qy.baidu.com/static/ge/login.html#/) and open [Infoflow applications](http://qy.baidu.com/index.html#applist). 2. Register an application and note the **AgentID**. 3. In the **Setting** tab, create a management group. In address book permissions, add your structure and grant the app the needed permissions; add the app to the specified location. Add the required sensitive interface permissions. diff --git a/docs/provider/oauth/linkedin.md b/docs/provider/oauth/linkedin.md index 3155182c3..2eaa8aaf3 100644 --- a/docs/provider/oauth/linkedin.md +++ b/docs/provider/oauth/linkedin.md @@ -5,6 +5,8 @@ keywords: [LinkedIn, OAuth] authors: [ErikQQY] --- + + 1. Create an app at [LinkedIn Developers](https://www.linkedin.com/developers/apps/new). ![LinkedIn](/img/providers/OAuth/linkedin.png) diff --git a/docs/provider/oauth/weCom.md b/docs/provider/oauth/weCom.md index 785cc049c..fc58be59c 100644 --- a/docs/provider/oauth/weCom.md +++ b/docs/provider/oauth/weCom.md @@ -16,6 +16,7 @@ WeCom supports OAuth so users can sign in from the WeCom client. You can use **i | Agent ID | Application **AgentId** | :::info + - **Silent:** User clicks the link and is redirected to `redirect_URI?code=CODE&state=STATE`. - **Normal:** A consent page is shown; after the user authorizes, redirect to `redirect_uri?code=CODE&state=STATE`. diff --git a/docs/provider/web3/metamask.md b/docs/provider/web3/metamask.md index 23b8ff8b5..0d388a946 100644 --- a/docs/provider/web3/metamask.md +++ b/docs/provider/web3/metamask.md @@ -26,6 +26,7 @@ Users can sign in with MetaMask. Demo: :::tip + - Authorize only one Ethereum address per user; Casdoor binds one address per account. - To use a different address, disconnect the current one in Casdoor first, then sign in again with the new address. diff --git a/sidebars.js b/sidebars.js index 9023c846d..0deea3bf0 100644 --- a/sidebars.js +++ b/sidebars.js @@ -669,6 +669,7 @@ module.exports = { link: {type: "generated-index"}, items: [ "integration/python/JumpServer", + "integration/python/casbin-fastapi", ], }, ], diff --git a/static/data/ecosystem/Integrations.json b/static/data/ecosystem/Integrations.json index 58405bfdb..3be1b6825 100644 --- a/static/data/ecosystem/Integrations.json +++ b/static/data/ecosystem/Integrations.json @@ -417,6 +417,16 @@ ], "image": "/img/ecosystem/JS.png" }, + { + "title": "FastAPI", + "url": "https://casdoor.org/docs/integration/python/casbin-fastapi", + "description": "Decorator-based Casbin authorization and Casdoor OAuth2 authentication for FastAPI.", + "tags": [ + "Integration", + "Python" + ], + "image": "/img/ecosystem/python.png" + }, { "title": "React Admin", "url": "https://marmelab.com/react-admin", @@ -430,4 +440,4 @@ ], "image": "/img/ecosystem/RA.png" } -] \ No newline at end of file +]