| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- package com.nylc.touyan.auth;
- import com.nylc.touyan.datasource.DataSourceClient;
- import com.nylc.touyan.rbac.RbacService;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.stereotype.Service;
- import java.util.Collections;
- import java.util.Map;
- /**
- * 用户业务:注册、登录、按用户名查询。
- * 复用 {@link DataSourceClient} 访问底层数据源(当前为 SQLite),未来切换 MySQL 业务代码零改动。
- * 登录/注册时通过 {@link RbacService} 加载角色与权限并随 token(AuthUser)下发。
- */
- @Service
- public class UserService {
- private static final Logger log = LoggerFactory.getLogger(UserService.class);
- private final DataSourceClient dataSource;
- private final RbacService rbacService;
- private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
- public UserService(DataSourceClient dataSource, RbacService rbacService) {
- this.dataSource = dataSource;
- this.rbacService = rbacService;
- }
- public void initSchema() {
- dataSource.execute(
- "CREATE TABLE IF NOT EXISTS sys_user (" +
- "id INTEGER PRIMARY KEY AUTOINCREMENT," +
- "username TEXT NOT NULL UNIQUE," +
- "password TEXT NOT NULL," +
- "nickname TEXT," +
- "enabled INTEGER NOT NULL DEFAULT 1," +
- "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
- log.info("[auth] 用户表 sys_user 已就绪");
- }
- public AuthUser register(String username, String rawPassword, String nickname) {
- if (username == null || username.trim().isEmpty()) {
- throw new AuthException("BAD_REQUEST", "用户名不能为空");
- }
- if (rawPassword == null || rawPassword.length() < 6) {
- throw new AuthException("BAD_REQUEST", "密码长度至少 6 位");
- }
- Map<String, Object> exists = dataSource.queryForMap(
- "SELECT id FROM sys_user WHERE username = ?", username);
- if (exists != null) {
- throw new AuthException("USER_EXISTS", "用户名已被注册");
- }
- String hash = encoder.encode(rawPassword);
- int rows = dataSource.update(
- "INSERT INTO sys_user(username, password, nickname) VALUES(?, ?, ?)",
- username, hash, nickname);
- if (rows <= 0) {
- throw new AuthException("INTERNAL", "注册失败");
- }
- Long id = ((Number) dataSource.queryForObject(
- "SELECT id FROM sys_user WHERE username = ?", username)).longValue();
- assignDefaultRole(id);
- return buildAuthUser(id, username, nickname);
- }
- public AuthUser login(String username, String rawPassword) {
- Map<String, Object> row = dataSource.queryForMap(
- "SELECT id, username, password, nickname, enabled FROM sys_user WHERE username = ?",
- username);
- if (row == null) {
- throw new AuthException("BAD_CREDENTIALS", "用户名或密码错误");
- }
- Number enabled = (Number) row.get("enabled");
- if (enabled != null && enabled.intValue() == 0) {
- throw new AuthException("USER_DISABLED", "账号已被禁用");
- }
- String hash = String.valueOf(row.get("password"));
- if (!encoder.matches(rawPassword, hash)) {
- throw new AuthException("BAD_CREDENTIALS", "用户名或密码错误");
- }
- Long id = ((Number) row.get("id")).longValue();
- String nickname = (String) row.get("nickname");
- return buildAuthUser(id, username, nickname);
- }
- public AuthUser findByUsername(String username) {
- Map<String, Object> row = dataSource.queryForMap(
- "SELECT id, username, nickname FROM sys_user WHERE username = ?", username);
- if (row == null) return null;
- Long id = ((Number) row.get("id")).longValue();
- return buildAuthUser(id, username, (String) row.get("nickname"));
- }
- private AuthUser buildAuthUser(Long id, String username, String nickname) {
- RbacService.AuthSnapshot snapshot = rbacService.resolve(id);
- return new AuthUser(id, username, nickname, snapshot.getRoles(), snapshot.getPermissions());
- }
- private void assignDefaultRole(Long userId) {
- Map<String, Object> role = dataSource.queryForMap(
- "SELECT id FROM sys_role WHERE code = 'USER'");
- if (role != null) {
- rbacService.assignUserRoles(userId, Collections.singletonList(
- ((Number) role.get("id")).longValue()));
- }
- }
- }
|