diff --git a/maxkey-starter/maxkey-starter-passkey/build.gradle b/maxkey-starter/maxkey-starter-passkey/build.gradle index 6b38226a4..89431f236 100644 --- a/maxkey-starter/maxkey-starter-passkey/build.gradle +++ b/maxkey-starter/maxkey-starter-passkey/build.gradle @@ -6,29 +6,10 @@ dependencies { implementation project(":maxkey-commons:maxkey-common") implementation project(":maxkey-commons:maxkey-crypto") - implementation project(":maxkey-commons:maxkey-ldap") implementation project(":maxkey-commons:maxkey-core") implementation project(":maxkey-entity") implementation project(":maxkey-persistence") implementation project(":maxkey-authentications:maxkey-authentication-core") implementation project(":maxkey-authentications:maxkey-authentication-provider") - // WebAuthn library for Passkey support - implementation "com.webauthn4j:webauthn4j-core:${webauthn4jVersion}" - implementation "com.webauthn4j:webauthn4j-util:${webauthn4jVersion}" - - // WebAuthn4J 的必需传递依赖 - implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" - implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" - implementation "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" - implementation "commons-codec:commons-codec:${commonscodecVersion}" - implementation "org.bouncycastle:bcprov-jdk18on:${bouncycastleVersion}" - implementation "org.bouncycastle:bcpkix-jdk18on:${bouncycastleVersion}" - implementation "org.slf4j:slf4j-api:${slf4jVersion}" - - // 其他可能需要的依赖 - implementation "org.apache.commons:commons-lang3:${commonslang3Version}" -} - -configurations.all { transitive = false } \ No newline at end of file +} \ No newline at end of file diff --git a/maxkey-starter/maxkey-starter-passkey/src/main/resources/META-INF/spring.factories b/maxkey-starter/maxkey-starter-passkey/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 9145698cd..000000000 --- a/maxkey-starter/maxkey-starter-passkey/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -# Spring Boot 2.x 兼容性配置 -# 自动配置类 -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.dromara.maxkey.passkey.autoconfigure.PasskeyAutoConfiguration \ No newline at end of file diff --git a/maxkey-starter/maxkey-starter-passkey/src/main/resources/application-passkey.yml b/maxkey-starter/maxkey-starter-passkey/src/main/resources/application-passkey.yml deleted file mode 100644 index d6a430c1b..000000000 --- a/maxkey-starter/maxkey-starter-passkey/src/main/resources/application-passkey.yml +++ /dev/null @@ -1,165 +0,0 @@ -# MaxKey Passkey 模块配置示例 -# 将此配置添加到主应用的 application.yml 中 - -maxkey: - passkey: - # 是否启用 Passkey 功能 - enabled: true - - # RP (Relying Party) 配置 - relying-party: - # RP 名称,显示给用户 - name: "MaxKey" - # RP ID,通常是域名(生产环境必须配置为实际域名) - id: "localhost" - # RP 图标 URL(可选) - icon: "/static/images/maxkey-logo.png" - - # 认证器配置 - authenticator: - # 认证器附件偏好:platform(平台认证器), cross-platform(跨平台认证器), null(无偏好) - attachment: "platform" - # 用户验证要求:required(必需), preferred(首选), discouraged(不鼓励) - user-verification: "required" - # 证明偏好:none(无), indirect(间接), direct(直接) - attestation: "none" - # 是否要求驻留密钥(可发现凭据) - require-resident-key: false - - # 挑战配置 - challenge: - # 挑战长度(字节) - length: 32 - # 挑战过期时间(分钟) - expire-minutes: 5 - # 操作超时时间(毫秒) - timeout-ms: 60000 - # 是否自动清理过期挑战 - auto-cleanup: true - # 清理间隔(小时) - cleanup-interval-hours: 1 - - # 用户限制配置 - user-limits: - # 每个用户最大 Passkey 数量 - max-passkeys-per-user: 5 - # 是否允许重复注册相同设备 - allow-duplicate-devices: false - - # 会话配置 - session: - # 认证会话过期时间(分钟) - auth-session-expire-minutes: 30 - # 是否启用会话管理 - enabled: true - -# 日志配置(可选) -logging: - level: - # Passkey 模块日志级别 - org.dromara.maxkey.passkey: INFO - # WebAuthn 相关日志 - com.webauthn4j: WARN - -# 数据源配置(如果使用独立数据源) -# spring: -# datasource: -# passkey: -# url: jdbc:mysql://localhost:3306/maxkey_passkey -# username: maxkey -# password: maxkey -# driver-class-name: com.mysql.cj.jdbc.Driver - -# 缓存配置(可选,用于挑战缓存) -# spring: -# cache: -# type: redis -# redis: -# host: localhost -# port: 6379 -# database: 1 -# timeout: 2000ms -# lettuce: -# pool: -# max-active: 8 -# max-idle: 8 -# min-idle: 0 - -# 安全配置 -security: - # CORS 配置(如果需要跨域支持) - cors: - allowed-origins: - - "https://your-domain.com" - - "http://localhost:3000" # 开发环境 - allowed-methods: - - GET - - POST - - PUT - - DELETE - - OPTIONS - allowed-headers: - - "*" - allow-credentials: true - -# 监控配置(可选) -management: - endpoints: - web: - exposure: - include: - - health - - info - - metrics - - passkey # 自定义 Passkey 监控端点 - endpoint: - health: - show-details: when-authorized - metrics: - tags: - application: maxkey-passkey - -# 生产环境配置示例 ---- -spring: - profiles: production - -maxkey: - passkey: - relying-party: - # 生产环境必须使用实际域名 - id: "auth.yourcompany.com" - name: "Your Company SSO" - authenticator: - # 生产环境建议使用更严格的验证 - user-verification: "required" - attestation: "indirect" - challenge: - # 生产环境可以使用更短的过期时间 - expire-minutes: 3 - timeout-ms: 30000 - session: - # 生产环境可以使用更短的会话时间 - auth-session-expire-minutes: 15 - -# 开发环境配置示例 ---- -spring: - profiles: development - -maxkey: - passkey: - relying-party: - id: "localhost" - authenticator: - # 开发环境可以放宽验证要求 - user-verification: "preferred" - challenge: - # 开发环境使用更长的过期时间便于调试 - expire-minutes: 10 - timeout-ms: 120000 - -logging: - level: - org.dromara.maxkey.passkey: DEBUG - root: INFO \ No newline at end of file diff --git a/maxkey-starter/maxkey-starter-passkey/src/main/resources/sql/passkey-schema.sql b/maxkey-starter/maxkey-starter-passkey/src/main/resources/sql/passkey-schema.sql deleted file mode 100644 index c7440941c..000000000 --- a/maxkey-starter/maxkey-starter-passkey/src/main/resources/sql/passkey-schema.sql +++ /dev/null @@ -1,107 +0,0 @@ --- Passkey模块数据库表结构 --- 用于存储用户Passkey凭据和认证挑战信息 - --- 用户Passkey凭据表 -CREATE TABLE mxk_user_passkeys ( - ID VARCHAR(40) NOT NULL, - USER_ID VARCHAR(40) NOT NULL COMMENT '用户ID', - CREDENTIAL_ID VARCHAR(1024) NOT NULL COMMENT 'WebAuthn凭据ID', - PUBLIC_KEY TEXT NOT NULL COMMENT '公钥信息', - SIGNATURE_COUNT BIGINT DEFAULT 0 COMMENT '签名计数器', - AAGUID VARCHAR(100) COMMENT '认证器AAGUID', - DISPLAY_NAME VARCHAR(200) COMMENT '显示名称', - DEVICE_TYPE VARCHAR(50) DEFAULT 'platform' COMMENT '设备类型:platform/cross-platform', - CREATED_DATE DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - LAST_USED_DATE DATETIME COMMENT '最后使用时间', - STATUS INT DEFAULT 1 COMMENT '状态:0-禁用,1-启用', - INST_ID VARCHAR(40) DEFAULT '1' COMMENT '机构ID', - PRIMARY KEY (ID), - UNIQUE KEY UK_USER_CREDENTIAL (USER_ID, CREDENTIAL_ID), - KEY IDX_USER_ID (USER_ID), - KEY IDX_CREDENTIAL_ID (CREDENTIAL_ID(255)), - KEY IDX_STATUS (STATUS), - KEY IDX_INST_ID (INST_ID) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户Passkey凭据表'; - --- 添加索引优化查询性能 -CREATE INDEX IDX_USER_STATUS ON mxk_user_passkeys(USER_ID, STATUS); -CREATE INDEX IDX_CREATED_DATE ON mxk_user_passkeys(CREATED_DATE); -CREATE INDEX IDX_LAST_USED ON mxk_user_passkeys(LAST_USED_DATE); - --- Passkey认证挑战表 -CREATE TABLE mxk_passkey_challenges ( - ID VARCHAR(40) NOT NULL, - USER_ID VARCHAR(40) COMMENT '用户ID(可为空,支持无用户名登录)', - CHALLENGE VARCHAR(1024) NOT NULL COMMENT '挑战字符串', - CHALLENGE_TYPE VARCHAR(20) NOT NULL COMMENT '挑战类型:REGISTRATION/AUTHENTICATION', - SESSION_ID VARCHAR(100) COMMENT '会话ID', - CREATED_DATE DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - EXPIRE_DATE DATETIME NOT NULL COMMENT '过期时间', - STATUS INT DEFAULT 0 COMMENT '状态:0-未使用,1-已使用', - INST_ID VARCHAR(40) DEFAULT '1' COMMENT '机构ID', - PRIMARY KEY (ID), - KEY IDX_USER_ID (USER_ID), - KEY IDX_CHALLENGE_TYPE (CHALLENGE_TYPE), - KEY IDX_SESSION_ID (SESSION_ID), - KEY IDX_EXPIRE_DATE (EXPIRE_DATE), - KEY IDX_STATUS (STATUS), - KEY IDX_INST_ID (INST_ID) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Passkey认证挑战表'; - --- 添加复合索引优化查询 -CREATE INDEX IDX_CHALLENGE_STATUS ON mxk_passkey_challenges(CHALLENGE_TYPE, STATUS); -CREATE INDEX IDX_USER_TYPE ON mxk_passkey_challenges(USER_ID, CHALLENGE_TYPE); -CREATE INDEX IDX_EXPIRE_STATUS ON mxk_passkey_challenges(EXPIRE_DATE, STATUS); - --- 为现有用户表添加Passkey相关字段(可选方案) --- 如果选择在现有mxk_userinfo表中添加字段,可以使用以下SQL: -/* -ALTER TABLE mxk_userinfo ADD COLUMN PASSKEY_ENABLED INT DEFAULT 0 COMMENT 'Passkey功能是否启用:0-禁用,1-启用'; -ALTER TABLE mxk_userinfo ADD COLUMN PASSKEY_COUNT INT DEFAULT 0 COMMENT '用户Passkey数量'; -ALTER TABLE mxk_userinfo ADD COLUMN LAST_PASSKEY_LOGIN DATETIME COMMENT '最后一次Passkey登录时间'; - --- 添加索引 -CREATE INDEX IDX_PASSKEY_ENABLED ON mxk_userinfo(PASSKEY_ENABLED); -CREATE INDEX IDX_LAST_PASSKEY_LOGIN ON mxk_userinfo(LAST_PASSKEY_LOGIN); -*/ - --- 创建清理过期挑战的存储过程 -DELIMITER // -CREATE PROCEDURE CleanExpiredPasskeyChallenges() -BEGIN - DECLARE affected_rows INT DEFAULT 0; - - -- 删除过期的挑战记录 - DELETE FROM mxk_passkey_challenges - WHERE EXPIRE_DATE < NOW(); - - -- 获取影响的行数 - SET affected_rows = ROW_COUNT(); - - -- 记录清理结果 - SELECT CONCAT('Cleaned ', affected_rows, ' expired passkey challenges') AS result; -END // -DELIMITER ; - --- 创建定时清理事件(可选) -/* -CREATE EVENT IF NOT EXISTS CleanPasskeyChallengesEvent -ON SCHEDULE EVERY 1 HOUR -DO - CALL CleanExpiredPasskeyChallenges(); -*/ - --- 插入一些示例数据(仅用于测试) -/* -INSERT INTO mxk_user_passkeys ( - ID, USER_ID, CREDENTIAL_ID, PUBLIC_KEY, DISPLAY_NAME, DEVICE_TYPE, INST_ID -) VALUES ( - 'test-passkey-001', - 'admin', - 'test-credential-id-001', - 'test-public-key-data', - 'Test Passkey Device', - 'platform', - '1' -); -*/ \ No newline at end of file diff --git a/sql/v4.1.9/passkey_tables.sql b/sql/v4.1.9/passkey_tables.sql new file mode 100644 index 000000000..43c007e66 --- /dev/null +++ b/sql/v4.1.9/passkey_tables.sql @@ -0,0 +1,52 @@ +-- MaxKey Passkey 模块数据库表创建脚本 +-- 创建用户 Passkey 表和挑战表 + +-- 用户 Passkey 表 +CREATE TABLE IF NOT EXISTS mxk_user_passkeys ( + id VARCHAR(40) NOT NULL COMMENT '主键ID', + user_id VARCHAR(40) NOT NULL COMMENT '用户ID', + credential_id VARCHAR(500) NOT NULL COMMENT '凭据ID(Base64编码)', + public_key TEXT NOT NULL COMMENT '公钥数据(Base64编码)', + display_name VARCHAR(100) COMMENT '显示名称', + device_type VARCHAR(50) DEFAULT 'unknown' COMMENT '设备类型', + signature_count BIGINT DEFAULT 0 COMMENT '签名计数器', + created_date DATETIME NOT NULL COMMENT '创建时间', + last_used_date DATETIME COMMENT '最后使用时间', + aaguid VARCHAR(100) COMMENT 'AAGUID', + inst_id VARCHAR(40) DEFAULT '1' COMMENT '机构ID', + status INT DEFAULT 1 COMMENT '状态:1-正常,0-禁用', + PRIMARY KEY (id), + UNIQUE KEY uk_credential_id (credential_id), + KEY idx_user_id (user_id), + KEY idx_inst_id (inst_id), + KEY idx_created_date (created_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户Passkey凭据表'; + +-- Passkey 挑战表 +CREATE TABLE IF NOT EXISTS mxk_passkey_challenges ( + id VARCHAR(40) NOT NULL COMMENT '挑战ID', + user_id VARCHAR(40) COMMENT '用户ID(认证时可为空)', + challenge TEXT NOT NULL COMMENT '挑战数据(Base64编码)', + challenge_type VARCHAR(20) NOT NULL COMMENT '挑战类型:REGISTRATION-注册,AUTHENTICATION-认证', + created_date DATETIME NOT NULL COMMENT '创建时间', + expires_date DATETIME NOT NULL COMMENT '过期时间', + status INT DEFAULT 0 COMMENT '状态:0-未使用,1-已使用', + inst_id VARCHAR(40) DEFAULT '1' COMMENT '机构ID', + PRIMARY KEY (id), + KEY idx_user_id (user_id), + KEY idx_challenge_type (challenge_type), + KEY idx_expires_date (expires_date), + KEY idx_inst_id (inst_id), + KEY idx_status (status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Passkey挑战表'; + +-- 创建索引以优化查询性能 +CREATE INDEX idx_user_passkeys_user_status ON mxk_user_passkeys(user_id, status); +CREATE INDEX idx_passkey_challenges_expires_status ON mxk_passkey_challenges(expires_date, status); +CREATE INDEX idx_passkey_challenges_user_type ON mxk_passkey_challenges(user_id, challenge_type); + +-- 插入示例数据(可选) +-- INSERT INTO mxk_user_passkeys (id, user_id, credential_id, public_key, display_name, device_type, signature_count, created_date, inst_id) +-- VALUES ('test_passkey_1', 'test_user_1', 'test_credential_id_1', 'test_public_key_1', 'Test Device', 'platform', 0, NOW(), '1'); + +COMMIT; \ No newline at end of file