feat: add dev password auto registration
Some checks failed
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-04-28 14:46:18 +08:00
parent fb965a1207
commit 1d319ba916
6 changed files with 175 additions and 8 deletions

View File

@@ -1382,6 +1382,36 @@ mod tests {
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
#[tokio::test]
async fn password_entry_dev_auto_register_creates_unknown_phone_when_enabled() {
let config = AppConfig {
dev_password_entry_auto_register_enabled: true,
..AppConfig::default()
};
let app = build_router(AppState::new(config).expect("state should build"));
let first_response =
password_login_request(app.clone(), "13800138023", TEST_PASSWORD).await;
let first_status = first_response.status();
let first_body = first_response
.into_body()
.collect()
.await
.expect("first response body should collect")
.to_bytes();
let first_payload: Value =
serde_json::from_slice(&first_body).expect("first response body should be valid json");
let second_response = password_login_request(app, "13800138023", TEST_PASSWORD).await;
assert_eq!(first_status, StatusCode::OK);
assert!(first_payload["token"].as_str().is_some());
assert_eq!(
first_payload["user"]["loginMethod"],
Value::String("password".to_string())
);
assert_eq!(second_response.status(), StatusCode::OK);
}
#[tokio::test]
async fn password_entry_logs_in_existing_phone_user_and_sets_refresh_cookie() {
let state = AppState::new(AppConfig::default()).expect("state should build");

View File

@@ -29,6 +29,7 @@ pub struct AppConfig {
pub refresh_cookie_same_site: String,
pub refresh_session_ttl_days: u32,
pub auth_store_path: PathBuf,
pub dev_password_entry_auto_register_enabled: bool,
pub sms_auth_enabled: bool,
pub sms_auth_provider: String,
pub sms_endpoint: String,
@@ -118,6 +119,7 @@ impl Default for AppConfig {
refresh_cookie_same_site: "Lax".to_string(),
refresh_session_ttl_days: 30,
auth_store_path: PathBuf::from(DEFAULT_AUTH_STORE_PATH),
dev_password_entry_auto_register_enabled: false,
sms_auth_enabled: false,
sms_auth_provider: "mock".to_string(),
sms_endpoint: "dypnsapi.aliyuncs.com".to_string(),
@@ -273,6 +275,11 @@ impl AppConfig {
if let Some(auth_store_path) = read_first_non_empty_env(&["GENARRATIVE_AUTH_STORE_PATH"]) {
config.auth_store_path = PathBuf::from(auth_store_path);
}
if let Some(enabled) =
read_first_bool_env(&["GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED"])
{
config.dev_password_entry_auto_register_enabled = enabled;
}
if let Some(sms_auth_enabled) = read_first_bool_env(&["SMS_AUTH_ENABLED"]) {
config.sms_auth_enabled = sms_auth_enabled;

View File

@@ -26,14 +26,19 @@ pub async fn password_entry(
headers: HeaderMap,
Json(payload): Json<PasswordEntryRequest>,
) -> Result<impl IntoResponse, AppError> {
let result = state
.password_entry_service()
.execute(PasswordEntryInput {
phone_number: payload.phone,
password: payload.password,
})
.await
.map_err(map_password_entry_error)?;
let input = PasswordEntryInput {
phone_number: payload.phone,
password: payload.password,
};
let result = if state.config.dev_password_entry_auto_register_enabled {
state
.password_entry_service()
.execute_with_dev_registration(input)
.await
} else {
state.password_entry_service().execute(input).await
}
.map_err(map_password_entry_error)?;
let session_client = resolve_session_client_context(&headers);
let signed_session = create_password_auth_session(&state, &result.user, &session_client)?;
state