Skip to content

Commit 8712fd9

Browse files
committed
chore: update docs and add example
1 parent 1b9da9a commit 8712fd9

File tree

4 files changed

+206
-3
lines changed

4 files changed

+206
-3
lines changed

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "casdoor-sdk-rust"
3-
version = "1.0.1"
3+
version = "1.0.2"
44
edition = "2021"
55
license = "Apache-2.0"
66
description = "A Casdoor SDK (contain APIs) with more complete interfaces and better usability."
@@ -11,7 +11,9 @@ homepage = "https://casdoor.org"
1111
keywords = ["iam", "auth", "sso", "oidc", "casdoor"]
1212
authors = ["Dmitrii Mastitckii <[email protected]>"]
1313

14-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14+
[dev-dependencies]
15+
actix-web-httpauth = "0.8.2"
16+
actix-web = { version = "4.9.0" }
1517

1618
[dependencies]
1719
serde = { version = "1", features = ["derive"] }

README.md

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Or add the following line to your Cargo.toml:
3434
casdoor-sdk-rust = "1"
3535
```
3636

37-
## Example
37+
## Example init Casdoor config
3838

3939
```rust
4040
#[cfg(test)]
@@ -86,3 +86,103 @@ nCCJHBcAyFnm1hdvdwEdH33jDBjNB6ciotJZrf/3VYaIWSalADosHAgMWfXuWP+h
8686
}
8787
}
8888
```
89+
90+
## Example with `actix_web_httpauth` and `actix_web`
91+
92+
```rust
93+
use actix_web::{error, post, HttpResponse, web::{Bytes, Data}, dev::ServiceRequest, HttpServer, App};
94+
use actix_web_httpauth::{middleware::HttpAuthentication, extractors::bearer::BearerAuth};
95+
use casdoor_sdk_rust::{AuthSdk, BasicTokenType, Config};
96+
use oauth2::{TokenIntrospectionResponse, TokenResponse};
97+
use serde::{Deserialize, Serialize};
98+
99+
#[derive(Serialize, Deserialize)]
100+
struct NewToken {
101+
access_token: String,
102+
token_type: BasicTokenType,
103+
expires_in: Option<u64>,
104+
refresh_token: String,
105+
scopes: String,
106+
// This field is not implementing in OAuth2, thats it's an extra field
107+
// and its only use in OpenID Connect
108+
id_token: String
109+
}
110+
111+
async fn validation(
112+
req: ServiceRequest,
113+
credentials: Option<BearerAuth>
114+
) -> Result<ServiceRequest, (error::Error, ServiceRequest)> {
115+
match credentials {
116+
Some(token) => {
117+
let auth_sdk = req.app_data::<Data<AuthSdk>>().unwrap();
118+
119+
let bearer_token = auth_sdk.parse_jwt_token(token.token());
120+
121+
match bearer_token {
122+
Ok(tk) => {
123+
println!("request from: {:?}", tk.user);
124+
// https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
125+
// if token is not active it's not valid
126+
let flag = auth_sdk.introspect_access_token(token.token().to_string()).await.unwrap();
127+
128+
if flag.active() {
129+
Ok(req)
130+
} else {
131+
Err((error::ErrorUnauthorized("token must be active, refresh it"), req))
132+
}
133+
}
134+
Err(e) => {
135+
Err((error::ErrorUnauthorized(format!("bad bearer: {}", e.to_string())), req))
136+
}
137+
}
138+
},
139+
None => {
140+
Err((error::ErrorBadRequest("request is not valid"), req))
141+
}
142+
}
143+
}
144+
145+
#[post("/refresh_token")]
146+
pub async fn refresh_token(bytes: Bytes, csd: Data<AuthSdk>) -> HttpResponse {
147+
match String::from_utf8(bytes.to_vec()) {
148+
Ok(token_string) => {
149+
let tk = csd.refresh_oauth_token(token_string).await.unwrap();
150+
let tk_struct = NewToken{
151+
access_token: tk.access_token().secret().to_owned(),
152+
token_type: tk.token_type().to_owned(),
153+
expires_in: Some(tk.expires_in().unwrap().as_secs()),
154+
refresh_token: tk.refresh_token().unwrap().secret().to_owned(),
155+
scopes: tk.scopes().unwrap()[0].to_string(),
156+
id_token: tk.extra_fields().id_token.to_string(),
157+
};
158+
159+
let tk_answer_json = serde_json::to_string(&tk_struct).unwrap();
160+
HttpResponse::Ok().body(tk_answer_json)
161+
}
162+
Err(e) => {
163+
HttpResponse::BadRequest().body(e.to_string())
164+
}
165+
}
166+
}
167+
168+
fn init_casdoor() -> AuthSdk {
169+
let app = Config::from_toml("./casdoor.toml").unwrap();
170+
app.into_sdk().authn()
171+
}
172+
173+
#[actix_web::main]
174+
async fn main() -> std::io::Result<()> {
175+
HttpServer::new(move || {
176+
let auth = HttpAuthentication::with_fn(validation);
177+
let auth_sdk = init_casdoor();
178+
179+
App::new()
180+
.service(refresh_token)
181+
.app_data(auth_sdk)
182+
.wrap(auth)
183+
})
184+
.bind(("127.0.0.1", 8080))?
185+
.run()
186+
.await
187+
}
188+
```

examples/actix_web.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use actix_web::{error, post, HttpResponse, web::{Bytes, Data}, dev::ServiceRequest, HttpServer, App};
2+
use actix_web_httpauth::{middleware::HttpAuthentication, extractors::bearer::BearerAuth};
3+
use casdoor_sdk_rust::{AuthSdk, BasicTokenType, Config};
4+
use oauth2::{TokenIntrospectionResponse, TokenResponse};
5+
use serde::{Deserialize, Serialize};
6+
7+
#[derive(Serialize, Deserialize)]
8+
struct NewToken {
9+
access_token: String,
10+
token_type: BasicTokenType,
11+
expires_in: Option<u64>,
12+
refresh_token: String,
13+
scopes: String,
14+
// This field is not implementing in OAuth2, that is an extra field
15+
// and its only use in OpenID Connect
16+
id_token: String
17+
}
18+
19+
async fn validation(
20+
req: ServiceRequest,
21+
credentials: Option<BearerAuth>
22+
) -> Result<ServiceRequest, (error::Error, ServiceRequest)> {
23+
match credentials {
24+
Some(token) => {
25+
let auth_sdk = req.app_data::<Data<AuthSdk>>().unwrap();
26+
27+
let bearer_token = auth_sdk.parse_jwt_token(token.token());
28+
29+
match bearer_token {
30+
Ok(tk) => {
31+
println!("request from: {:?}", tk.user);
32+
// https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
33+
// if token is not active it's not valid
34+
let flag = auth_sdk.introspect_access_token(token.token().to_string()).await.unwrap();
35+
36+
if flag.active() {
37+
Ok(req)
38+
} else {
39+
Err((error::ErrorUnauthorized("token must be active, refresh it"), req))
40+
}
41+
}
42+
Err(e) => {
43+
Err((error::ErrorUnauthorized(format!("bad bearer: {}", e.to_string())), req))
44+
}
45+
}
46+
},
47+
None => {
48+
Err((error::ErrorBadRequest("request is not valid"), req))
49+
}
50+
}
51+
}
52+
53+
#[post("/refresh_token")]
54+
pub async fn refresh_token(bytes: Bytes, csd: Data<AuthSdk>) -> HttpResponse {
55+
match String::from_utf8(bytes.to_vec()) {
56+
Ok(token_string) => {
57+
let tk = csd.refresh_oauth_token(token_string).await.unwrap();
58+
let tk_struct = NewToken{
59+
access_token: tk.access_token().secret().to_owned(),
60+
token_type: tk.token_type().to_owned(),
61+
expires_in: Some(tk.expires_in().unwrap().as_secs()),
62+
refresh_token: tk.refresh_token().unwrap().secret().to_owned(),
63+
scopes: tk.scopes().unwrap()[0].to_string(),
64+
id_token: tk.extra_fields().id_token.to_string(),
65+
};
66+
67+
let tk_answer_json = serde_json::to_string(&tk_struct).unwrap();
68+
HttpResponse::Ok().body(tk_answer_json)
69+
}
70+
Err(e) => {
71+
HttpResponse::BadRequest().body(e.to_string())
72+
}
73+
}
74+
}
75+
76+
fn init_casdoor() -> AuthSdk {
77+
let app = Config::from_toml("./casdoor.toml").unwrap();
78+
app.into_sdk().authn()
79+
}
80+
81+
#[actix_web::main]
82+
async fn main() -> std::io::Result<()> {
83+
HttpServer::new(move || {
84+
let auth = HttpAuthentication::with_fn(validation);
85+
let auth_sdk = init_casdoor();
86+
87+
App::new()
88+
.service(refresh_token)
89+
.app_data(auth_sdk)
90+
.wrap(auth)
91+
})
92+
.bind(("127.0.0.1", 8080))?
93+
.run()
94+
.await
95+
}

examples/casdoor.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
endpoint="http://localhost:8000"
2+
client_id="client_id"
3+
client_secret="client_secret"
4+
org_name="org_name"
5+
app_name="app_name"
6+
certificate="""certificate value"""

0 commit comments

Comments
 (0)