UserService.java 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package com.nylc.touyan.auth;
  2. import com.nylc.touyan.datasource.DataSourceClient;
  3. import com.nylc.touyan.rbac.RbacService;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  7. import org.springframework.stereotype.Service;
  8. import java.util.Collections;
  9. import java.util.Map;
  10. /**
  11. * 用户业务:注册、登录、按用户名查询。
  12. * 复用 {@link DataSourceClient} 访问底层数据源(当前为 SQLite),未来切换 MySQL 业务代码零改动。
  13. * 登录/注册时通过 {@link RbacService} 加载角色与权限并随 token(AuthUser)下发。
  14. */
  15. @Service
  16. public class UserService {
  17. private static final Logger log = LoggerFactory.getLogger(UserService.class);
  18. private final DataSourceClient dataSource;
  19. private final RbacService rbacService;
  20. private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  21. public UserService(DataSourceClient dataSource, RbacService rbacService) {
  22. this.dataSource = dataSource;
  23. this.rbacService = rbacService;
  24. }
  25. public void initSchema() {
  26. dataSource.execute(
  27. "CREATE TABLE IF NOT EXISTS sys_user (" +
  28. "id INTEGER PRIMARY KEY AUTOINCREMENT," +
  29. "username TEXT NOT NULL UNIQUE," +
  30. "password TEXT NOT NULL," +
  31. "nickname TEXT," +
  32. "enabled INTEGER NOT NULL DEFAULT 1," +
  33. "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
  34. log.info("[auth] 用户表 sys_user 已就绪");
  35. }
  36. public AuthUser register(String username, String rawPassword, String nickname) {
  37. if (username == null || username.trim().isEmpty()) {
  38. throw new AuthException("BAD_REQUEST", "用户名不能为空");
  39. }
  40. if (rawPassword == null || rawPassword.length() < 6) {
  41. throw new AuthException("BAD_REQUEST", "密码长度至少 6 位");
  42. }
  43. Map<String, Object> exists = dataSource.queryForMap(
  44. "SELECT id FROM sys_user WHERE username = ?", username);
  45. if (exists != null) {
  46. throw new AuthException("USER_EXISTS", "用户名已被注册");
  47. }
  48. String hash = encoder.encode(rawPassword);
  49. int rows = dataSource.update(
  50. "INSERT INTO sys_user(username, password, nickname) VALUES(?, ?, ?)",
  51. username, hash, nickname);
  52. if (rows <= 0) {
  53. throw new AuthException("INTERNAL", "注册失败");
  54. }
  55. Long id = ((Number) dataSource.queryForObject(
  56. "SELECT id FROM sys_user WHERE username = ?", username)).longValue();
  57. assignDefaultRole(id);
  58. return buildAuthUser(id, username, nickname);
  59. }
  60. public AuthUser login(String username, String rawPassword) {
  61. Map<String, Object> row = dataSource.queryForMap(
  62. "SELECT id, username, password, nickname, enabled FROM sys_user WHERE username = ?",
  63. username);
  64. if (row == null) {
  65. throw new AuthException("BAD_CREDENTIALS", "用户名或密码错误");
  66. }
  67. Number enabled = (Number) row.get("enabled");
  68. if (enabled != null && enabled.intValue() == 0) {
  69. throw new AuthException("USER_DISABLED", "账号已被禁用");
  70. }
  71. String hash = String.valueOf(row.get("password"));
  72. if (!encoder.matches(rawPassword, hash)) {
  73. throw new AuthException("BAD_CREDENTIALS", "用户名或密码错误");
  74. }
  75. Long id = ((Number) row.get("id")).longValue();
  76. String nickname = (String) row.get("nickname");
  77. return buildAuthUser(id, username, nickname);
  78. }
  79. public AuthUser findByUsername(String username) {
  80. Map<String, Object> row = dataSource.queryForMap(
  81. "SELECT id, username, nickname FROM sys_user WHERE username = ?", username);
  82. if (row == null) return null;
  83. Long id = ((Number) row.get("id")).longValue();
  84. return buildAuthUser(id, username, (String) row.get("nickname"));
  85. }
  86. private AuthUser buildAuthUser(Long id, String username, String nickname) {
  87. RbacService.AuthSnapshot snapshot = rbacService.resolve(id);
  88. return new AuthUser(id, username, nickname, snapshot.getRoles(), snapshot.getPermissions());
  89. }
  90. private void assignDefaultRole(Long userId) {
  91. Map<String, Object> role = dataSource.queryForMap(
  92. "SELECT id FROM sys_role WHERE code = 'USER'");
  93. if (role != null) {
  94. rbacService.assignUserRoles(userId, Collections.singletonList(
  95. ((Number) role.get("id")).longValue()));
  96. }
  97. }
  98. }