- Введение
- casbin-rs / poem-casbin
- Промежуточное программное обеспечение для контроля доступа Casbin Poem
- Поэма Casbin Middleware
- Установите .
- Требование
- Напишите службу hello-world с помощью стихотворения
- Интеграция с базовым промежуточным программным обеспечением auth
- Интеграция с промежуточным ПО poem-casbin
- Резюме
- greenhandatsjtu / poem-casbin-demo
- Демонстрация интеграции casbin-rs с веб-сервисами poem с помощью промежуточного ПО poem-casbin
- poem-casbin-demo
- Введение
- Написание сервиса hello-world с помощью poem
Введение
Casbin-rs — это библиотека авторизации, поддерживающая такие модели управления доступом, как ACL, RBAC, ABAC, написанная на языке Rust.
Poem — это полнофункциональный и простой в использовании веб-фреймворк с языком программирования Rust.
В этом руководстве мы будем интегрировать casbin-rs с веб-сервисами poem, используя промежуточное ПО poem-casbin.
casbin-rs / poem-casbin
Промежуточное программное обеспечение для контроля доступа Casbin Poem
Поэма Casbin Middleware
Промежуточное ПО управления доступом Casbin для фреймворка poem
Установите .
Добавьте его в Cargo.toml
poem = "1.3.31" poem-casbin-auth = "0.x.x" tokio = { version = "1.17.0", features = ["rt-multi-thread", "macros"] }
Требование
Casbin берет на себя только контроль разрешений, поэтому вам необходимо реализовать Authentication Middleware
для идентификации пользователя.
Вы должны поместить poem_casbin_auth::CasbinVals
, который содержит subject
(имя пользователя) и domain
(опционально) в Extension.
Например:
use poem::{ Endpoint, EndpointExt, Middleware, Request, Result, }; use poem_casbin_auth::CasbinVals; pub struct FakeAuth; pub struct FakeAuthMiddleware<E> { ep: E, } impl<E: Endpoint> Middleware<E> for FakeAuth { type Output = FakeAuthMiddleware<E>; fn transform(&self, ep: E)
…
Напишите службу hello-world с помощью стихотворения
Сначала создайте крейт cargo, затем добавьте следующие зависимости в Cargo.toml
:
tokio = { version = "1.20.0", features = ["rt-multi-thread", "macros"] }
poem = "1.3.35"
Добавьте следующий код в main.rs
.
use poem::{get, handler, listener::TcpListener, web::Path, Route, Server};
use std::env;
#[handler]
fn pen1() -> String {
String::from("I'm pen 1")
}
#[handler]
fn pen2() -> String {
String::from("I'm pen 2")
}
#[handler]
fn book(Path(id): Path<String>) -> String {
format!("I'm book {}", id)
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
if env::var_os("RUST_LOG").is_none() {
env::set_var("RUST_LOG", "poem=debug");
}
let app = Route::new()
.at("/pen/1", get(pen1))
.at("/pen/2", get(pen2))
.at("/book/:id", get(book));
Server::new(TcpListener::bind("127.0.0.1:3000"))
.name("poem-casbin-demo")
.run(app)
.await
}
Есть 3 конечные точки, /pen/1
, /pen/2
, и /book/:id
. Все довольно просто, верно? Давайте запустим наш сервис, введите cargo run
и наш сервис будет доступен по адресу 127.0.0.1:3000
.
Давайте используем curl
для тестирования нашего сервиса:
Интеграция с базовым промежуточным программным обеспечением auth
Обратите внимание, что casbin-poem — это промежуточное ПО авторизации, а не аутентификации. Casbin отвечает только за контроль разрешений, поэтому нам необходимо реализовать промежуточное ПО аутентификации для идентификации пользователя.
В этой части мы интегрируем базовое промежуточное ПО аутентификации в наш сервис.
Для начала добавьте следующую зависимость в Cargo.toml
:
poem-casbin-auth = { git = "https://github.com/casbin-rs/poem-casbin.git" }
Затем создайте файл с именем auth.rs
и добавьте в него следующий код:
use poem::{
http::StatusCode,
web::{
headers,
headers::{authorization::Basic, HeaderMapExt},
},
Endpoint, Error, Middleware, Request, Result,
};
use poem_casbin_auth::CasbinVals;
pub struct BasicAuth;
impl<E: Endpoint> Middleware<E> for BasicAuth {
type Output = BasicAuthEndpoint<E>;
fn transform(&self, ep: E) -> Self::Output {
BasicAuthEndpoint { ep }
}
}
pub struct BasicAuthEndpoint<E> {
ep: E,
}
#[poem::async_trait]
impl<E: Endpoint> Endpoint for BasicAuthEndpoint<E> {
type Output = E::Output;
async fn call(&self, mut req: Request) -> Result<Self::Output> {
if let Some(auth) = req.headers().typed_get::<headers::Authorization<Basic>>() {
let vals = CasbinVals {
subject: String::from(auth.username()),
domain: None,
};
req.extensions_mut().insert(vals);
self.ep.call(req).await
} else {
Err(Error::from_status(StatusCode::UNAUTHORIZED))
}
}
}
В этом моде мы реализуем базовый auth middleware, для простоты, здесь мы не проверяем имя пользователя и пароль, вместо этого мы просто вставляем CasbinVals
с предоставленным именем пользователя в Extension
, так что poem-casbin middleware может извлечь информацию об идентификации. Если запрос не имеет basic auth, то промежуточное ПО вернет 401 Unauthorized.
Затем давайте интегрируем это промежуточное ПО basic auth с нашим сервисом. Во-первых, добавьте следующий код в main.rs
:
mod auth;
use poem_casbin_auth::CasbinVals;
Затем добавьте новый обработчик для подтверждения того, что наше промежуточное ПО auth правильно вставило информацию об идентификации:
#[handler]
fn user(data: Data<&CasbinVals>) -> String {
format!("Hello, {}", &data.subject)
}
Наконец, перепишите функцию main
, чтобы добавить конечную точку /user
и оберните все конечные точки базовым промежуточным ПО auth, теперь это выглядит так:
let app = Route::new()
.at("/pen/1", get(pen1))
.at("/pen/2", get(pen2))
.at("/book/:id", get(book))
.at("/user", get(user))
.with(casbin_middleware)
.with(auth::BasicAuth);
Теперь давайте снова используем curl
для тестирования нашего сервиса.
Как вы видите, если мы не предоставим basic auth при доступе к нашему сервису, мы получим 401 Unauthorized. Наш запрос будет прерван промежуточным ПО basic auth. Давайте отправлять запросы с помощью basic auth:
curl -u alice:123 localhost:3000/book/1
Теперь мы можем получить ответ как обычно. Похоже, что наше промежуточное ПО basic auth работает хорошо.
Интеграция с промежуточным ПО poem-casbin
В последней части мы интегрируем промежуточное ПО poem-casbin с нашим сервисом.
Во-первых, нам нужно предоставить файлы conf и policy в корневой директории проекта.
rbac_with_pattern_model.conf
выглядит следующим образом:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && regexMatch(r.act, p.act)
rbac_with_pattern_policy.csv
выглядит как:
p, alice, /pen/1, GET
p, book_admin, book_group, GET
p, pen_admin, pen_group, GET
,,,
g, alice, book_admin,
g, bob, pen_admin,
g2, /book/:id, book_group,
g2, /pen/:id, pen_group,
Эта политика означает:
- Для Алисы
- может получить доступ к
/pen/1
- является
book_admin
, поэтому может получить доступ к/book/:id
- может получить доступ к
- Для Боба:
- является
pen_admin
, поэтому может получить доступ к/pen/:id
.
- является
Теперь давайте сосредоточимся на main.rs
, сначала добавим в него следующий код:
use poem_casbin_auth::casbin::function_map::key_match2;
use poem_casbin_auth::casbin::{CoreApi, DefaultModel, FileAdapter};
use poem_casbin_auth::{CasbinService, CasbinVals};
Затем перепишите функцию main
, чтобы обернуть наш сервис с помощью промежуточного ПО poem-casbin:
let m = DefaultModel::from_file("rbac_with_pattern_model.conf")
.await
.unwrap();
let a = FileAdapter::new("rbac_with_pattern_policy.csv");
let casbin_middleware = CasbinService::new(m, a).await.unwrap();
casbin_middleware
.write()
.await
.get_role_manager()
.write()
.matching_fn(Some(key_match2), None);
let app = Route::new()
.at("/pen/1", get(pen1))
.at("/pen/2", get(pen2))
.at("/book/:id", get(book))
.at("/user", get(user))
.with(casbin_middleware)
.with(auth::BasicAuth);
Здесь мы сначала читаем conf и политику, затем создаем casbin_middleware
и изменяем matching_fn
на key_match
для соответствия пути подстановочного символа (например, /:id
). И наконец, мы оборачиваем все конечные точки casbin_middleware
.
Вот и вся работа, которую мы должны сделать, чтобы интегрировать промежуточное ПО poem-casbin в наш сервис, довольно просто, не так ли?
Опять же, давайте используем curl
для тестирования нашего сервиса:
Если alice захочет получить доступ к /pen/2
, она получит 403 Forbidden, потому что ей не разрешен доступ к этой конечной точке.
Аналогично, Боб не может получить доступ к /book/2
:
Все в порядке, когда оба пользователя посылают запросы к конечным точкам, к которым они могут получить доступ:
Резюме
В этом руководстве мы написали веб-сервис hello-world, используя poem, затем интегрировали в него базовый auth и промежуточное ПО casbin-poem. Это довольно простой проект, состоящий всего из ~100 LOC, его код можно найти в этом репозитории:
greenhandatsjtu / poem-casbin-demo
Демонстрация интеграции casbin-rs с веб-сервисами poem с помощью промежуточного ПО poem-casbin
poem-casbin-demo
Демонстрация интеграции casbin-rs с веб-сервисами poem с использованием промежуточного ПО poem-casbin
Введение
Casbin-rs — это библиотека авторизации, поддерживающая такие модели управления доступом, как ACL, RBAC, ABAC, написанная на языке Rust.
Poem — это полнофункциональный и простой в использовании веб-фреймворк с языком программирования Rust.
В этом руководстве мы будем интегрировать casbin-rs с веб-сервисами poem, используя промежуточное ПО poem-casbin.
Написание сервиса hello-world с помощью poem
Сначала создайте крейт cargo, затем добавьте следующие зависимости в Cargo.toml
:
tokio = { version = "1.20.0", features = ["rt-multi-thread", "macros"] } poem = "1.3.35"
Добавьте следующий код в main.rs
.
use poem::{get, handler, listener::TcpListener, web::Path, Route, Server}; use std::env; #[handler] fn pen1() -> String { String::from("I'm pen 1"
…