6次发布
新版本 0.1.3 | 2024年8月12日 |
---|---|
0.1.2 |
|
0.0.31 | 2024年8月1日 |
0.0.30 | 2024年7月31日 |
#70 在 身份验证
872 每月下载
78KB
1.5K SLoC
some-auth
此crate提供API服务中常用的身份验证逻辑(用户和角色管理、仓库、带有刷新认证的JWT),开箱即用。有关此crate使用的安全方法的更详细描述,请参阅安全方法。
目前,该crate主要关注异步使用,特别是Axum。
此crate可选地(启用axum-auth
功能)建议身份验证中间件,可以在每个认证用户或仅对指定的角色允许访问。
目前,PostgreSQL仓库实现可用(启用pg-repository
功能),用于存储用户和刷新令牌。在开发过程中,可能会将其他实现(例如MongoDB)的一些功能添加到crate中。
该crate目前正在早期开发中,未来版本可能会实施一些破坏性更改。
设置
将some-auth crate添加到您的项目中(使用下面将要描述的axum-auth
和pg-repository
可选功能)
cargo add some-auth --features axum-auth,pg-repository
要使用crate的功能,需要创建一个UserService,它使用UserServiceBuilder创建。
默认构建器
最简单的方法是使用some_auth::default_builder()方法,该方法返回具有以下属性的默认构建器
构建器需要指定AuthRepository trait的实现,使用use_repository
方法。在此示例中,我们将使用PgAuthRepository
(PostgreSQL仓库),它可通过pg-repository
功能获得。要查看表模式,请参阅src/repository/pg_repository.sql
示例
let repository = Arc::new(PgAuthRepository::create("postgresql://postgres:postgres@localhost:5432/postgres".to_string()).await.unwrap());
let jwt_token_settings = JwtTokenSettings {
access_tokens_secret: "supersecret".to_string(),
access_tokens_lifetime: TimeDelta::minutes(10),
refresh_tokens_secret: "supersecrettoo".to_string(),
refresh_tokens_lifetime: TimeDelta::days(7)
};
let user_service = some_auth::default_builder()
.configure_jwt(jwt_token_settings)
.use_repository(repository)
.build()
.unwrap();
PgAuthRepository 包含以下实现:impl<TAuthUser: AuthUser + fmt::Debug + Send + Sync> AuthRepository<TAuthUser> for PgRepository
其中 AuthUser 在此情况下是 User
#[async_trait]
impl<TAuthUser: AuthUser + fmt::Debug + Send + Sync> AuthRepository<TAuthUser> for PgRepository {
async fn add_user(&self, user: &TAuthUser) -> Result<i32, String> {
let client = open_connection(&self.conn_string).await.map_err(|err| err.to_string())?;
let created_res = client.query_one("\
INSERT INTO users (username, pwd_hash, blocked, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5)
RETURNING id;",
&[
&user.username(),
&user.pwd_hash(),
&user.blocked(),
&user.created_at(),
&user.updated_at()
])
.await
.map_err(|err| err.to_string())?;
Ok(created_res.get("id"))
}
...other methods...
}
因此,为了正确地在关系数据库(例如示例中的 postgres)中使用实现过的仓库,需要在那里创建一些表
您还可以使用 Axum 身份验证中间件来保护您的 API(仅在有 features = [ "axum-auth" ]
功能的情况下可用)
/// Controls if user is authenticated and checks their role according to [`RoleFilter`]
pub async fn auth_middleware<'a, TAuthUser: AuthUser + fmt::Debug + Send + Sync>(
State(state): State<Arc<UserServiceState<TAuthUser>>>,
req: Request,
next: Next,
role_filter: Option<RoleFilter<'a>>
) -> Result<Response, AuthError> { ... }
let user_service_state = Arc::new(UserServiceState { user_service });
let router = Router::new()
.route("/public-route", post(public_route_handler))
.route("/authenticated-users-route", post(authenticated_users_route_handler))
.route_layer(middleware::from_fn_with_state(user_service_state, |state, req, next| some_auth::auth_middleware(state, req, next, None))) // None as this route is available for every authenticated user
.route("/role-specified-route", post(role_specified_route_handler))
.route_layer(middleware::from_fn_with_state(user_service_state, |state, req, next| some_auth::auth_middleware(state, req, next, Some(vec!["admin", "backoffice"])))) // this route is available only for authenticated users with "admin" or "backoffice" role
手动设置
要手动设置 UserSerice,需要使用
pub fn builder<TAuthUser: AuthUser + fmt::Debug + Send + Sync>() -> UserServiceBuilder<TAuthUser>
并使用以下方法设置所有所需的配置
/// Sets [`CredentialValidator`] which will be used to valudate [`AuthUser`] credentials in [`UserService`]
pub fn set_credential_validator(mut self, validator: CredentialValidator) -> Self
/// Sets jwt algorithm which will be used in [`UserService`]
pub fn set_jwt_algorithm(mut self, algorithm: Algorithm) -> Self
/// Sets jwt token settings which will be used in [`UserService`]
pub fn configure_jwt(mut self, jwt_token_settings: JwtTokenSettings) -> Self
/// Sets the repository which will be used in [`UserService`]
pub fn use_repository(mut self, repository: Arc<dyn AuthRepository<TAuthUser> + Sync + Send>) -> Self
安全方法
JWT
此crate使用 jsonwebtoken crate 进行JWT。现在,仅提供对称加密算法(不同SHA的HMAC)。不对称算法可能在将来可用。JWT秘密和生命周期可配置。对于需要刷新令牌的操作,还有一个额外的检查,以确定提供的刷新令牌是否实际(也请参阅 Storing the secrets)。
用户验证
为了提高应用程序的安全性,默认的 CredentialValidator 对于用户凭证有以下规则
- 至少5个字符,拉丁字母和数字的组合,用户名至少有一个字母
- 至少12个字符,拉丁大小写字母、数字和特殊符号的组合
但当然,有时它可能太强(或太弱)。在这种情况下,可以配置自己的 CredentialValidator。
存储秘密
用户模型(因此,存储库中的用户)使用bcrypt哈希密码,这可以有效防止暴力攻击。
刷新令牌也存储在存储库中,以确保用户提供的刷新令牌是真实的。为了避免数据库中的“裸”刷新令牌,它们也进行了哈希处理,但使用SHA-256(在令牌需要快速哈希检查的情况下更有用,同时与密码相比,暴力破解“随机”令牌更困难)。将来可能会实现禁用或更改令牌哈希算法的功能。
依赖关系
~7–19MB
~276K SLoC