Casdoor SDK
简介
Compared to the standard OIDC protocol, Casdoor provides more functionalities in its SDK, like user management, resource uploading, etc. Connecting to Casdoor via Casdoor SDK costs more time than using a standard OIDC client library but will provide the best flexibility and the most powerful API.
Casdoor SDK可分为两类:
- Frontend SDK: Like Javascript SDK, Vue SDK for websites, Android or iOS SDKs for Apps, etc. Casdoor supports providing authentication for both websites and mobile Apps.
- Backend SDK: SDKs for backend languages like Go, Java, Node.js, Python, PHP, etc.
tip
If your website is developed in a frontend and backend separated manner, then you can use the Javascript SDK: casdoor-js-sdk
or the Vue SDK: casdoor-vue-sdk
to integrate Casdoor in frontend. If your web application is a traditional website developed by JSP or PHP, you can just use the backend SDKs only. See an example: casdoor-python-vue-sdk-example
Frontend SDK | 描述 | SDK code | Example code |
---|---|---|---|
Javascript SDK | 适用于网页 | casdoor-js-sdk | Casnode, Casbin-OA, Confita |
Android SDK | For Android apps | casdoor-android-sdk | |
iOS SDK | For iOS apps | casdoor-ios-sdk | |
React SDK | For React websites | casdoor-js-sdk | Casnode, Casbin-OA, Confita |
Vue SDK | For Vue websites | casdoor-vue-sdk | casdoor-python-vue-sdk-example |
Angular SDK | For angular 1.0, 2.0 websites | casdoor-angular-sdk | |
uni-app SDK | For uni-app apps | casdoor-uniapp-sdk | casdoor-uniapp-example |
Next, use one of the following backend SDKs based on the language of your backend:
Backend SDK | Description | Sdk code | Example code |
---|---|---|---|
Go SDK | For Go backends | casdoor-go-sdk | Casnode, Casbin-OA, Confita |
Java SDK | For Java backends | casdoor-java-sdk | casdoor-spring-boot-starter, casdoor-spring-boot-example |
Node.js SDK | For Node.js backends | casdoor-nodejs-sdk | |
Python SDK | For Python backends | casdoor-python-sdk | casdoor-python-vue-sdk-example |
PHP SDK | For PHP backends | casdoor-php-sdk | wordpress-casdoor-plugin |
.NET SDK | For ASP.NET backends | casdoor-dotnet-sdk | casdoor-dotnet-sdk-example |
Dart SDK | For Dart backends | casdoor-dart-sdk |
For a full list of the official Casdoor SDKs, please see: https://github.com/casdoor?q=sdk&type=all&language=&sort=
如何使用 Casdoor SDK ?
1. 后端 SDK 配置
When your application starts up, you need to initialize the Casdoor SDK config by calling the InitConfig()
function with required parameters. Take casdoor-go-sdk as example: https://github.com/casbin/casnode/blob/6d4c55f5c9a3c4bd8c85f2493abad3553b9c7ac0/controllers/account.go#L51-L64
var CasdoorEndpoint = "https://door.casdoor.com"
var ClientId = "541738959670d221d59d"
var ClientSecret = "66863369a64a5863827cf949bab70ed560ba24bf"
var CasdoorOrganization = "casbin"
var CasdoorApplication = "app-casnode"
//go:embed token_jwt_key.pem
var JwtPublicKey string
func init() {
auth.InitConfig(CasdoorEndpoint, ClientId, ClientSecret, JwtPublicKey, CasdoorOrganization, CasdoorApplication)
}
All the parameters for InitConfig()
are explained as follows:
参数 | 是否必须 | 描述 |
---|---|---|
endpoint | 否 | Casdoor 的服务URL,例如: https://door.casdoor.com or http://localhost:8000 |
clientId | 确定 | Casdoor 应用程序的客户端 ID |
clientSecret | 确定 | Casdoor 应用程序的客户端密钥 |
jwtPublicKey | 确定 | Casdoor 应用程序证书的公钥 |
organizationName | 确定 | Casdoor 组织的名称 |
applicationName | 否 | Casdoor 应用程序的名称 |
tip
The jwtPublicKey
can be managed in the Certs
page as below.
You can find the public key in the cert edit page, copy it or download it for the sdk.
Then you can select the cert in the application edit page.
2. 前端配置
First, install casdoor-js-sdk
via NPM or Yarn:
npm install casdoor-js-sdk
Or:
yarn add casdoor-js-sdk
Then define the following utility functions (better in a global JS file like Setting.js
):
import Sdk from "casdoor-js-sdk";
export function initCasdoorSdk(config) {
CasdoorSdk = new Sdk(config);
}
export function getSignupUrl() {
return CasdoorSdk.getSignupUrl();
}
export function getSigninUrl() {
return CasdoorSdk.getSigninUrl();
}
export function getUserProfileUrl(userName, account) {
return CasdoorSdk.getUserProfileUrl(userName, account);
}
export function getMyProfileUrl(account) {
return CasdoorSdk.getMyProfileUrl(account);
}
export function getMyResourcesUrl(account) {
return CasdoorSdk.getMyProfileUrl(account).replace("/account?", "/resources?");
}
export function signin() {
return CasdoorSdk.signin(ServerUrl);
}
export function showMessage(type, text) {
if (type === "") {
return;
} else if (type === "success") {
message.success(text);
} else if (type === "error") {
message.error(text);
}
}
export function goToLink(link) {
window.location.href = link;
}
In the entrance file of your frontend code (like index.js
or app.js
in React), you need to initialize the casdoor-js-sdk
by calling the InitConfig()
function with required parameters. The first 4 parameters should use the same value as the Casdoor backend SDK. The last parameter redirectPath
is relative path for the redirected URL, returned from Casdoor's login page.
const config = {
serverUrl: "https://door.casdoor.com",
clientId: "014ae4bd048734ca2dea",
organizationName: "casbin",
appName: "app-casnode",
redirectPath: "/callback",
};
xxx.initCasdoorSdk(config);
(Optional) Because we are using React as example, so our /callback
path is hitting the React route, we use the following React component to receive the /callback
call and sends to the backend. You can ignore this step if you are redirecting to backend directly (like in JSP or PHP).
import React from "react";
import {Button, Result, Spin} from "antd";
import {withRouter} from "react-router-dom";
import * as Setting from "./Setting";
class AuthCallback extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
msg: null,
};
}
componentWillMount() {
this.login();
}
login() {
Setting.signin().then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", `Logged in successfully`);
Setting.goToLink("/");
} else {
this.setState({
msg: res.msg,
});
}
});
}
render() {
return (
<div style={{textAlign: "center"}}>
{this.state.msg === null ? (
<Spin
size="large"
tip="Signing in..."
style={{paddingTop: "10%"}}
/>
) : (
<div style={{display: "inline"}}>
<Result
status="error"
title="Login Error"
subTitle={this.state.msg}
extra={[
<Button type="primary" key="details">
Details
</Button>,
<Button key="help">Help</Button>,
]}
/>
</div>
)}
</div>
);
}
}
export default withRouter(AuthCallback);
3. 获取登录 URL
Next you can show the "Sign up" and "Sign in" buttons or links to your users. The URLs can either be retrieved in the frontend or backend. See more details at: /docs/basic/core-concepts#login-urls
4. 获取并验证访问令牌
Here are the steps:
- The user clicks the login URL and is redirected to Casdoor's login page, like:
https://door.casdoor.com/login/oauth/authorize?client_id=014ae4bd048734ca2dea&response_type=code&redirect_uri=https%3A%2F%2Fforum.casbin.com%2Fcallback&scope=read&state=app-casnode
- The user enters username & password and clicks
Sign In
(or just click the third-party login button likeSign in with GitHub
). - The user is redirected back to your application with the authorization code issued by Casdoor ( like:
https://forum.casbin.com?code=xxx&state=yyy
), your application's backend needs to exchange the authorization code with the access token and verify that the access token is valid and issued by Casdoor. The functionsGetOAuthToken()
andParseJwtToken()
are provided by Casdoor backend SDK.
The following code shows how to get and verify the access token. For a real example of Casnode (a forum website written in Go), see: https://github.com/casbin/casnode/blob/6d4c55f5c9a3c4bd8c85f2493abad3553b9c7ac0/controllers/account.go#L51-L64
// 从重定向 URL 的 GET 参数中获取代码和状态
code := c.Input().Get("code")
state := c.Input().Get("state")
// 用代码和状态交换访问令牌
token, err := auth.GetOAuthToken(code, state)
if err != nil {
panic(err)
}
// 验证访问令牌
claims, err := auth.ParseJwtToken(token.AccessToken)
if err != nil {
panic(err)
}
If ParseJwtToken()
finishes with no error, then the user has successfully logged into the application. The returned claims
can be used to identity the user later.
4. 用访问令牌识别用户
info
This part is actually your application's own business logic and not part of OIDC, OAuth or Casdoor. We just provide good practices as a lot of people don't know what to do for next step.
In Casdoor, access token is usually identical as ID token. They are the same thing. So the access token contains all information for the logged-in user.
The variable claims
returned by ParseJwtToken()
is defined as:
Type Claims struct
User
AccessToken string `json:"accessToken"
jwt.RegisteredClaims
}
User
: the User object, containing all information for the logged-in user, see definition at: /docs/basic/core-concepts#userAccessToken
: the access token string.jwt.RegisteredClaim
: JWT需要一些其他值。
At this moment, the application usually has two ways to remember the user session: session
and JWT
.
Session
The Method to set session varies greatly depending on the language and web framework. E.g., Casnode uses Beego web framework and set session by calling: c.SetSessionUser()
.
token, err := auth.GetOAuthToken(code, state)
if err != nil {
panic(err)
}
claims, err := auth.ParseJwtToken(token.AccessToken)
if err != nil {
panic(err)
}
claims.AccessToken = token.AccessToken
c.SetSessionUser(claims) // 设置会话
JWT
The accessToken
returned by Casdoor is actually a JWT. So if your application uses JWT to keep user session, just use the access token directly for it:
- 将访问令牌发送到前端,在本地存储浏览器等地方保存。
- 让浏览器为每个请求发送访问令牌到后端。
- Call
ParseJwtToken()
or your own function to verify the access token and get logged-in user information in your backend.
5. (可选) 与用户表的互动
This part is provided by Casdoor Public API
and not part of the OIDC or OAuth.
Casdoor Backend SDK provides a lot of helper functions, not limited to:
GetUser(name string)
: 通过用户名获取用户。GetUsers()
: 获取所有用户。AddUser()
: 添加一个用户。UpdateUser()
: 更新一个用户。DeleteUser()
: 删除一个用户。CheckUserPassword(auth.User)
: 检查用户的密码。
These functions are implemented by making RESTful calls against Casdoor Public API
. If a function is not provided in Casdoor Backend SDK, you can make RESTful calls by yourself.