Merge pull request #29 from nagisa77/codex/add-password-strength-policy-configuration

Add password strength configuration
This commit is contained in:
Tim
2025-07-01 13:45:51 +08:00
committed by GitHub
5 changed files with 71 additions and 1 deletions

View File

@@ -24,7 +24,7 @@ OpenIsle 基于 Spring Boot 构建,提供社区后台常见的注册、登录
* **角色权限**:内置 `ADMIN``USER`,管理员接口以 `/api/admin/**` 提供
* **文章与评论**:支持分类、评论及多级回复
* **图片上传**`ImageUploader` 可接入不同云存储,示例中实现了腾讯云 COS
* **灵活配置**:数据库、邮件、存储等信息均可通过环境变量或 `application.properties` 设置
* **灵活配置**:数据库、邮件、存储及密码强度均可通过环境变量或 `application.properties` 设置
* **简洁架构**:业务、持久化与安全配置清晰分层,便于扩展
## 🚀 快速开始
@@ -45,6 +45,7 @@ OpenIsle 基于 Spring Boot 构建,提供社区后台常见的注册、登录
- `COS_BASE_URL`:腾讯云 COS 访问域名
- `JWT_SECRET`JWT 签名密钥
- `JWT_EXPIRATION`JWT 过期时间(毫秒)
- `PASSWORD_STRENGTH`密码强度LOW、MEDIUM、HIGH
2. 启动项目:
```bash

View File

@@ -0,0 +1,7 @@
package com.openisle.model;
public enum PasswordStrength {
LOW,
MEDIUM,
HIGH
}

View File

@@ -0,0 +1,57 @@
package com.openisle.service;
import com.openisle.model.PasswordStrength;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class PasswordValidator {
private final PasswordStrength strength;
public PasswordValidator(@Value("${app.password.strength:LOW}") PasswordStrength strength) {
this.strength = strength;
}
public void validate(String password) {
if (password == null || password.isEmpty()) {
throw new IllegalArgumentException("Password cannot be empty");
}
switch (strength) {
case MEDIUM:
checkMedium(password);
break;
case HIGH:
checkHigh(password);
break;
default:
// LOW, nothing beyond non-empty
}
}
private void checkMedium(String password) {
if (password.length() < 8) {
throw new IllegalArgumentException("Password must be at least 8 characters long");
}
if (!password.matches(".*[A-Za-z].*") || !password.matches(".*\\d.*")) {
throw new IllegalArgumentException("Password must contain letters and numbers");
}
}
private void checkHigh(String password) {
if (password.length() < 12) {
throw new IllegalArgumentException("Password must be at least 12 characters long");
}
if (!password.matches(".*[A-Z].*")) {
throw new IllegalArgumentException("Password must contain uppercase letters");
}
if (!password.matches(".*[a-z].*")) {
throw new IllegalArgumentException("Password must contain lowercase letters");
}
if (!password.matches(".*\\d.*")) {
throw new IllegalArgumentException("Password must contain numbers");
}
if (!password.matches(".*[^A-Za-z0-9].*")) {
throw new IllegalArgumentException("Password must contain special characters");
}
}
}

View File

@@ -2,6 +2,7 @@ package com.openisle.service;
import com.openisle.model.User;
import com.openisle.model.Role;
import com.openisle.service.PasswordValidator;
import com.openisle.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -15,9 +16,11 @@ import java.util.Random;
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final PasswordValidator passwordValidator;
private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public User register(String username, String email, String password) {
passwordValidator.validate(password);
// ── 先按用户名查 ──────────────────────────────────────────
Optional<User> byUsername = userRepository.findByUsername(username);
if (byUsername.isPresent()) {

View File

@@ -7,6 +7,8 @@ spring.jpa.hibernate.ddl-auto=update
# for jwt
app.jwt.secret=${JWT_SECRET:ChangeThisSecretKeyForJwt}
app.jwt.expiration=${JWT_EXPIRATION:86400000}
# Password strength: LOW, MEDIUM or HIGH
app.password.strength=${PASSWORD_STRENGTH:LOW}
# Post publish mode: DIRECT or REVIEW
app.post.publish-mode=${POST_PUBLISH_MODE:DIRECT}