2 个不稳定版本
0.2.0 | 2024年2月4日 |
---|---|
0.1.0 | 2022年8月29日 |
#173 在 认证
用于 moella
120KB
2.5K SLoC
kvarn-auth
一个用于 Kvarn 的快速、简单、可自定义的认证扩展。不可能自伤!
提供基于 JWT 的易于使用的认证助手,支持持久登录和验证服务器。
您提供一个异步回调,它给用户一定的授权级别。您可以根据 serde 返回任何结构化数据。JWT 会自动续订,因为服务器存储了一个凭证 cookie(使用服务器的私钥加密)。一切都可以配置。
⚠️ 注意:这个 crate 还未经过审计。我使用的所有依赖都经过了审计。自行承担风险。
不过,我个人确实在生产系统中使用这个。
前端使用
提供了一个用于登录、登出和获取用户当前状态的微型 JS 库。请查看它及其文档以获取更多详细信息。
验证服务器
这个库的一个重要特性是验证服务器。这使得可以将 kvarn-auth
部署到多个不同的物理服务器,而不必共享可以签发任何人的私钥。这是通过使用快速非对称加密实现的。有关更多信息,请参阅 ecdsa_sk
。
持久登录
除了常用的 JWT cookie 之外,kvarn-auth
还发送一个凭证 cookie。它包含使用服务器的密钥/私钥加密的用户凭证。当 JWT 过期时,这允许自动续订(使用 Kvarn 的优秀扩展系统)。凭证 cookie 被加密,以防止 XSS 攻击窃取用户的密码(用户可能在其他网站上重复使用),这是帮助用户的努力。
您可以通过启用 Builder::with_force_relog_on_ip_change
使任何 cookie 窃取都变得无用。我们将用户的 IP 嵌入 JWT 和凭证中,并且仅当 IP 相同时才允许它们。这可能会让用户感到烦恼(特别是如果您的用户群体主要是移动用户),但大大降低了账户被盗的风险。所以,可能用于银行 :)
版本
- 0.1.x -
kvarn v0.5
- 0.2.x -
kvarn v0.6
示例
# use kvarn::prelude::*;
// please use a strong random secret (>1024bits of entropy to be safe)
let secret = b"this secret protects all the JWTs and the credentials".to_vec();
let mut accounts: HashMap<String, String> = HashMap::new();
accounts.insert("icelk".into(), "password".into());
let auth_config = kvarn_auth::Builder::new()
// the authentication's scope is limited to routes starting with `/demo/`.
.with_cookie_path("/demo/")
.with_auth_page_name("/demo/auth")
// according to Kvarn's internal redirects, `/demo/login.` is shorthand for `/demo/login.html`
.with_show_auth_page_when_unauthorized("/demo/login.")
.build::<(), _, _>(
move |user, password, _addr, _req| {
let v = if accounts.get(user).map_or(false, |pass| pass == password) {
kvarn_auth::Validation::Authorized(kvarn_auth::AuthData::None)
} else {
kvarn_auth::Validation::Unauthorized
};
core::future::ready(v)
},
kvarn_auth::CryptoAlgo::EcdsaP256 { secret },
);
let mut extensions = kvarn::Extensions::new();
auth_config.mount(&mut extensions);
let login_status = auth_config.login_status();
extensions.add_prepare_single(
"/demo/api",
prepare!(
req,
host,
_path,
addr,
move |login_status: kvarn_auth::LoginStatusClosure<()>| {
let auth_data =
if let kvarn_auth::Validation::Authorized(ad) =
login_status(req, addr)
{
ad
} else {
return default_error_response(
StatusCode::UNAUTHORIZED,
host,
Some("log in at `/demo/login.html`"),
)
.await;
};
// continue with your API, with a guarantee
FatResponse::no_cache(Response::new(Bytes::new()))
}),
);
依赖项
约11-22MB
约299K SLoC