Ver código fonte

account 模块和 myblog 项目对齐

reghao 2 anos atrás
pai
commit
36ffc55498
17 arquivos alterados com 294 adições e 180 exclusões
  1. 20 20
      manager/src/main/java/cn/reghao/devops/manager/account/controller/UserController.java
  2. 16 0
      manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountAuthedToken.java
  3. 1 2
      manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountProfile.java
  4. 1 1
      manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountRole.java
  5. 8 1
      manager/src/main/java/cn/reghao/devops/manager/account/model/dto/CreateAccountDto.java
  6. 0 45
      manager/src/main/java/cn/reghao/devops/manager/account/model/dto/UserAddDTO.java
  7. 15 0
      manager/src/main/java/cn/reghao/devops/manager/account/model/po/User.java
  8. 45 1
      manager/src/main/java/cn/reghao/devops/manager/account/security/form/AccountAuthToken.java
  9. 3 2
      manager/src/main/java/cn/reghao/devops/manager/account/service/AccountAuthService.java
  10. 19 0
      manager/src/main/java/cn/reghao/devops/manager/account/service/AccountService.java
  11. 21 0
      manager/src/main/java/cn/reghao/devops/manager/account/service/AccountTokenService.java
  12. 0 20
      manager/src/main/java/cn/reghao/devops/manager/account/service/UserService.java
  13. 81 19
      manager/src/main/java/cn/reghao/devops/manager/account/service/impl/AccountAuthServiceImpl.java
  14. 42 39
      manager/src/main/java/cn/reghao/devops/manager/account/service/impl/AccountServiceImpl.java
  15. 13 6
      manager/src/main/java/cn/reghao/devops/manager/config/CacheConfig.java
  16. 7 3
      manager/src/main/java/cn/reghao/devops/manager/config/spring/AppLifecycle.java
  17. 2 21
      manager/src/test/java/AccountTest.java

+ 20 - 20
manager/src/main/java/cn/reghao/devops/manager/account/controller/UserController.java

@@ -1,11 +1,11 @@
 package cn.reghao.devops.manager.account.controller;
 
 import cn.reghao.devops.manager.account.model.dto.UpdatePasswordDto;
-import cn.reghao.devops.manager.account.model.dto.UserCreateDto;
+import cn.reghao.devops.manager.account.model.dto.CreateAccountDto;
 import cn.reghao.jutil.jdk.result.WebResult;
-import cn.reghao.devops.manager.account.model.dto.UserInfo;
-import cn.reghao.devops.manager.account.model.dto.UserRole;
-import cn.reghao.devops.manager.account.service.UserService;
+import cn.reghao.devops.manager.account.model.dto.AccountProfile;
+import cn.reghao.devops.manager.account.model.dto.AccountRole;
+import cn.reghao.devops.manager.account.service.AccountService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.http.MediaType;
@@ -25,17 +25,17 @@ import java.util.List;
 @RequestMapping("/api/rbac/user")
 @RestController
 public class UserController {
-    private final UserService userService;
+    private final AccountService accountService;
 
-    public UserController(UserService userService) {
-        this.userService = userService;
+    public UserController(AccountService accountService) {
+        this.accountService = accountService;
     }
 
     @PreAuthorize("hasRole('ROLE_ADMIN')")
     @ApiOperation(value = "创建用户")
     @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
-    public String createUser(@Validated UserCreateDto userCreateDto) {
-        userService.createUser(userCreateDto);
+    public String createUser(@Validated CreateAccountDto createAccountDto) {
+        accountService.createAccount(createAccountDto);
         return WebResult.success();
     }
 
@@ -54,30 +54,30 @@ public class UserController {
     @ApiOperation(value = "修改用户信息")
     @PostMapping(value = "/modify", produces = MediaType.APPLICATION_JSON_VALUE)
     @Deprecated
-    public String modifyUserInfo(@Validated UserInfo userInfo) {
-        userService.modifyUserInfo(userInfo);
+    public String updateAccountProfile(@Validated AccountProfile accountProfile) {
+        accountService.updateAccountProfile(accountProfile);
         return WebResult.success();
     }
 
     @ApiOperation(value = "修改用户信息")
     @PostMapping(value = "/edit", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String editUserInfo(@Validated UserInfo userInfo) {
-        //userService.modifyUserInfo(userInfo);
+    public String editUserInfo(@Validated AccountProfile accountProfile) {
+        //accountService.updateAccountProfile(accountProfile);
         return WebResult.success();
     }
 
     @PreAuthorize("hasRole('ROLE_ADMIN')")
     @ApiOperation(value = "删除用户")
     @DeleteMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String deleteUser(@PathVariable("id") Integer userId) {
-        userService.deleteUser(userId);
+    public String deleteAccount(@PathVariable("id") Integer userId) {
+        accountService.deleteAccount(userId);
         return WebResult.success();
     }
 
     @ApiOperation(value = "修改用户密码")
     @PostMapping(value = "/passwd", produces = MediaType.APPLICATION_JSON_VALUE)
     public String modifyPassword(@NotNull Integer id, @NotNull String newPassword) {
-        userService.modifyUserPassword(id, newPassword);
+        accountService.updateAccountPassword(id, newPassword);
         return WebResult.success();
     }
 
@@ -89,17 +89,17 @@ public class UserController {
 
     @ApiOperation(value = "分配用户角色")
     @PostMapping(value = "/role", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String assignRole(@Validated UserRole userRole) {
-        userService.setUserRoles(userRole);
+    public String assignRole(@Validated AccountRole accountRole) {
+        accountService.updateAccountRole(accountRole);
         return WebResult.success();
     }
 
     // TODO 暂不启用本功能
     @ApiOperation(value = "启用/禁用用户")
     @PostMapping(value = "/status/{enable}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String setUserStatus(@PathVariable("enable") Boolean enable,
+    public String updateAccountStatus(@PathVariable("enable") Boolean enable,
                                 @RequestParam(value = "ids") List<Integer> userIds) {
-        userIds.forEach(userId -> userService.setUserStatus(userId, enable));
+        userIds.forEach(userId -> accountService.updateAccountStatus(userId, enable));
         return WebResult.success();
     }
 }

+ 16 - 0
manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountAuthedToken.java

@@ -0,0 +1,16 @@
+package cn.reghao.devops.manager.account.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author reghao
+ * @date 2023-10-19 13:56:02
+ */
+@AllArgsConstructor
+@Getter
+public class AccountAuthedToken {
+    private Integer plat;
+    private String loginId;
+    private Integer userId;
+}

+ 1 - 2
manager/src/main/java/cn/reghao/devops/manager/account/model/dto/UserInfo.java → manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountProfile.java

@@ -10,12 +10,11 @@ import java.io.Serializable;
  * @date 2021-07-12 16:06:11
  */
 @Data
-public class UserInfo implements Serializable {
+public class AccountProfile implements Serializable {
     private static final long serialVersionUID = 1L;
     private Integer userId;
     @NotBlank(message = "用户名不能为空白字符串")
     private String screenName;
-    // TODO 验证邮箱和手机号码是否有效
     private String mobile;
     private String email;
     private Integer gender;

+ 1 - 1
manager/src/main/java/cn/reghao/devops/manager/account/model/dto/UserRole.java → manager/src/main/java/cn/reghao/devops/manager/account/model/dto/AccountRole.java

@@ -12,7 +12,7 @@ import java.util.Set;
  * @date 2021-07-14 09:37:16
  */
 @Data
-public class UserRole implements Serializable {
+public class AccountRole implements Serializable {
     private static final long serialVersionUID = 1L;
     private Integer userId;
     @NotNull(message = "用户角色不能为 NULL")

+ 8 - 1
manager/src/main/java/cn/reghao/devops/manager/account/model/dto/UserCreateDto.java → manager/src/main/java/cn/reghao/devops/manager/account/model/dto/CreateAccountDto.java

@@ -12,7 +12,7 @@ import javax.validation.constraints.NotNull;
  */
 @Setter
 @Getter
-public class UserCreateDto {
+public class CreateAccountDto {
     @NotBlank(message = "必须指定登录名")
     private String username;
     @NotBlank(message = "必须指定用户名")
@@ -21,4 +21,11 @@ public class UserCreateDto {
     private String password;
     @NotNull(message = "必须选择用户角色")
     private Integer roleId;
+
+    public CreateAccountDto(String username, String password) {
+        this.username = username;
+        this.screenName = username;
+        this.password = password;
+        this.roleId = 1;
+    }
 }

+ 0 - 45
manager/src/main/java/cn/reghao/devops/manager/account/model/dto/UserAddDTO.java

@@ -1,45 +0,0 @@
-package cn.reghao.devops.manager.account.model.dto;
-
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.Set;
-
-/**
- * @author reghao
- * @date 2021-09-13 17:12:59
- */
-@Data
-public class UserAddDTO implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    // 用户名和密码
-    @NotBlank(message = "登录名不能为空白字符串")
-    private String username;
-    @NotBlank(message = "密码不能为空白字符串")
-    private String password;
-    @NotEmpty(message = "必须指定角色")
-    @Size(min = 1, max = 1, message = "只能指定一个角色")
-    private Set<Integer> roleIds;
-
-    @NotBlank(message = "用户名不能为空白字符串")
-    private String screenName;
-    private int gender;
-    private String mobile;
-    private String email;
-
-    /*public User to() {
-        User user = new User();
-        user.setUsername(username);
-        user.setPassword(password);
-        //user.setRoleIds(roleIds);
-        user.setNickname(screenName);
-        user.setGender(gender);
-        user.setmobile(mobile);
-        user.setEmail(email);
-        return user;
-    }*/
-}

+ 15 - 0
manager/src/main/java/cn/reghao/devops/manager/account/model/po/User.java

@@ -8,6 +8,7 @@ import org.springframework.security.core.userdetails.UserDetails;
 
 import javax.persistence.*;
 import javax.validation.constraints.NotBlank;
+import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -35,6 +36,7 @@ public class User extends BaseEntity implements UserDetails {
     private String password;
     @Column(nullable = false)
     private String salt;
+    private LocalDateTime createAt;
 
     @ElementCollection(fetch = FetchType.EAGER)
     @CollectionTable(name = "sys_user_role")
@@ -58,6 +60,19 @@ public class User extends BaseEntity implements UserDetails {
         this.gender = 2;
     }
 
+    public User(String username, String password, String salt) {
+        this.username = username;
+        this.password = password;
+        this.salt = salt;
+        this.createAt = LocalDateTime.now();
+        this.role = Set.of("ROLE_ADMIN");
+        this.enabled = true;
+        this.locked = false;
+        this.screenName = username;
+        this.gender = 2;
+        this.avatarUrl = "/imgs/avatar.jpg";
+    }
+
     @Override
     public String getUsername() {
         return username;

+ 45 - 1
manager/src/main/java/cn/reghao/devops/manager/account/security/form/AccountAuthToken.java

@@ -2,8 +2,11 @@ package cn.reghao.devops.manager.account.security.form;
 
 import cn.reghao.devops.manager.account.model.po.User;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.SpringSecurityCoreVersion;
 
+import java.util.List;
+
 /**
  * 参考 org.springframework.security.authentication.UsernamePasswordAuthenticationToken 实现
  *
@@ -15,7 +18,9 @@ public class AccountAuthToken extends AbstractAuthenticationToken {
 
     // ~ Instance fields
     // ================================================================================================
+    private final String loginId;
     private final boolean rememberMe;
+    private final Integer userId;
     private final Object principal;
     private Object credentials;
 
@@ -30,10 +35,12 @@ public class AccountAuthToken extends AbstractAuthenticationToken {
      * will return <code>false</code>.
      *
      */
-    public AccountAuthToken(Boolean rememberMe, Object principal, Object credentials) {
+    public AccountAuthToken(String loginId, Boolean rememberMe, Object principal, Object credentials) {
         super(null);
         super.setAuthenticated(false);
+        this.loginId = loginId;
         this.rememberMe = rememberMe;
+        this.userId = null;
         this.principal = principal;
         this.credentials = credentials;
     }
@@ -53,17 +60,44 @@ public class AccountAuthToken extends AbstractAuthenticationToken {
         super(user.getAuthorities());
         super.setAuthenticated(true); // must use super, as we override
         super.setDetails(user);
+        this.loginId = authToken.getLoginId();
         this.rememberMe = authToken.isRememberMe();
+        this.userId = user.getId();
         this.principal = authToken.getPrincipal();
         this.credentials = authToken.getCredentials();
     }
 
+    /**
+     * 从 AccessToken 中恢复的已认证 Authentication 对象
+     *
+     * @param
+     * @return
+     * @date 2023-02-17 17:42:27
+     */
+    public AccountAuthToken(int plat, String loginId, int loginType, Object principal, List<GrantedAuthority> authorities) {
+        super(authorities);
+        super.setAuthenticated(true);
+        this.loginId = loginId;
+        this.rememberMe = false;
+        this.userId = Integer.parseInt((String) principal);
+        this.principal = principal;
+        this.credentials = null;
+    }
+
     // ~ Methods
     // ========================================================================================================
+    public String getLoginId() {
+        return loginId;
+    }
+
     public boolean isRememberMe() {
         return rememberMe;
     }
 
+    public Integer getUserId() {
+        return this.userId;
+    }
+
     @Override
     public Object getCredentials() {
         return this.credentials;
@@ -74,6 +108,16 @@ public class AccountAuthToken extends AbstractAuthenticationToken {
         return this.principal;
     }
 
+    /*@Override
+    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
+        if (isAuthenticated) {
+            throw new IllegalArgumentException(
+                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
+        }
+
+        super.setAuthenticated(false);
+    }*/
+
     @Override
     public void eraseCredentials() {
         super.eraseCredentials();

+ 3 - 2
manager/src/main/java/cn/reghao/devops/manager/account/service/AccountAuthService.java

@@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
 public interface AccountAuthService extends UserDetailsService {
     AccountAuthToken getPreAuthentication(@Validated AccountLoginDto userLoginDto) throws AuthenticationException;
     AccountAuthToken authByPassword(AccountAuthToken authToken);
-    AccountAuthToken authByVerifyCode(AccountAuthToken authToken);
-    AccountAuthToken authByThirdParty(AccountAuthToken authToken);
+    void setCookie(AccountAuthToken authToken, long timeout);
+    void clearCookie();
+    void logout();
 }

+ 19 - 0
manager/src/main/java/cn/reghao/devops/manager/account/service/AccountService.java

@@ -0,0 +1,19 @@
+package cn.reghao.devops.manager.account.service;
+
+import cn.reghao.devops.manager.account.model.dto.CreateAccountDto;
+import cn.reghao.devops.manager.account.model.dto.AccountProfile;
+import cn.reghao.devops.manager.account.model.dto.AccountRole;
+
+/**
+ * @author reghao
+ * @date 2020-06-19 16:36:53
+ */
+public interface AccountService {
+    void initAccount();
+    void createAccount(CreateAccountDto createAccountDto);
+    void updateAccountPassword(Integer userId, String newPassword);
+    void updateAccountProfile(AccountProfile accountProfile);
+    void updateAccountRole(AccountRole accountRole);
+    void updateAccountStatus(Integer userId, Boolean enable);
+    void deleteAccount(Integer userId);
+}

+ 21 - 0
manager/src/main/java/cn/reghao/devops/manager/account/service/AccountTokenService.java

@@ -0,0 +1,21 @@
+package cn.reghao.devops.manager.account.service;
+
+
+import cn.reghao.devops.manager.account.model.dto.AccountAuthedToken;
+import cn.reghao.devops.manager.account.security.form.AccountAuthToken;
+
+/**
+ * @author reghao
+ * @date 2023-02-16 14:57:49
+ */
+public interface AccountTokenService {
+    AccountAuthedToken getAuthedToken();
+    /**
+     * 从 cookie 或 token 中读取已认证用户的 AccountAuthToken
+     *
+     * @param
+     * @return
+     * @date 2023-10-19 18:38:43
+     */
+    AccountAuthToken getAuthToken(int tokenType, String userdata);
+}

+ 0 - 20
manager/src/main/java/cn/reghao/devops/manager/account/service/UserService.java

@@ -1,20 +0,0 @@
-package cn.reghao.devops.manager.account.service;
-
-import cn.reghao.devops.manager.account.model.dto.UserCreateDto;
-import cn.reghao.devops.manager.account.model.po.User;
-import cn.reghao.devops.manager.account.model.dto.UserInfo;
-import cn.reghao.devops.manager.account.model.dto.UserRole;
-
-/**
- * @author reghao
- * @date 2020-06-19 16:36:53
- */
-public interface UserService {
-    User getUser(String username);
-    void createUser(UserCreateDto userCreateDto);
-    void modifyUserPassword(Integer userId, String newPassword);
-    void modifyUserInfo(UserInfo userInfo);
-    void setUserRoles(UserRole userRole);
-    void setUserStatus(Integer userId, Boolean enable);
-    void deleteUser(Integer userId);
-}

+ 81 - 19
manager/src/main/java/cn/reghao/devops/manager/account/service/impl/AccountAuthServiceImpl.java

@@ -1,28 +1,40 @@
 package cn.reghao.devops.manager.account.service.impl;
 
+import cn.reghao.devops.manager.account.db.repository.UserRepository;
 import cn.reghao.devops.manager.account.model.dto.AccountLoginDto;
 import cn.reghao.devops.manager.account.model.po.User;
 import cn.reghao.devops.manager.account.security.exceptioin.AccountLoginException;
 import cn.reghao.devops.manager.account.security.form.AccountAuthToken;
 import cn.reghao.devops.manager.account.service.AccountAuthService;
-import cn.reghao.devops.manager.account.service.UserService;
+import cn.reghao.jutil.web.ServletUtil;
+import com.github.benmanes.caffeine.cache.Cache;
 import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.Cookie;
+
 /**
  * @author reghao
  * @date 2022-07-08 14:51:17
  */
 @Service
 public class AccountAuthServiceImpl implements AccountAuthService {
-    private final UserService userService;
+    private final String cookieName = "USERDATA";
+    private final String domain = "";
+    private final Cache<String, Object> caffeineCache;
+    private final UserRepository userRepository;
     private final PasswordEncoder passwordEncoder;
 
-    public AccountAuthServiceImpl(UserService userService, PasswordEncoder passwordEncoder) {
-        this.userService = userService;
+    public AccountAuthServiceImpl(Cache<String, Object> caffeineCache, UserRepository userRepository,
+                                  PasswordEncoder passwordEncoder) {
+        this.caffeineCache = caffeineCache;
+        this.userRepository = userRepository;
         this.passwordEncoder = passwordEncoder;
     }
 
@@ -31,12 +43,14 @@ public class AccountAuthServiceImpl implements AccountAuthService {
         String principal = userLoginDto.getUsername();
         String credential = userLoginDto.getPassword();
         Boolean rememberMe = userLoginDto.getRememberMe();
-        return new AccountAuthToken(rememberMe, principal, credential);
+
+        String loginId = ServletUtil.getSessionId();
+        return new AccountAuthToken(loginId, rememberMe, principal, credential);
     }
 
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
-        User user = userService.getUser(username);
+        User user = userRepository.findByUsername(username);
         if (user != null) {
             return user;
         } else {
@@ -65,22 +79,70 @@ public class AccountAuthServiceImpl implements AccountAuthService {
         return new AccountAuthToken(authToken, userDetail);
     }
 
-    /**
-     * TODO 手机号验证码登录, 手机号不存在则自动注册
-     *
-     * @param
-     * @return
-     * @date 2022-07-08 下午3:11
-     */
     @Override
-    public AccountAuthToken authByVerifyCode(AccountAuthToken authToken) {
-        String errMsg = "接口未实现";
-        throw new DisabledException(errMsg);
+    public void setCookie(AccountAuthToken authToken, long timeout) {
+        int userId = authToken.getUserId();
+        int plat = 1;
+        String loginId = authToken.getLoginId();
+
+        String userdata = String.format("%s:%s:%s", userId, plat, loginId);
+        Cookie cookie3 = generateCookie(cookieName, userdata, timeout);
+        ServletUtil.getResponse().addCookie(cookie3);
+
+        String loginSuccessKey = String.format("account:login:success:%s:%s:%s", userId, plat, loginId);
+        if (timeout == 0) {
+            timeout = 3600*24*30;
+        }
+        caffeineCache.put(loginSuccessKey, authToken);
+    }
+
+    private Cookie generateCookie(String name, String value, long timeout) {
+        String path = "/";
+
+        Cookie cookie = new Cookie(name, value);
+        if (timeout != 0) {
+            cookie.setMaxAge((int) timeout);
+        }
+        cookie.setDomain(domain);
+        cookie.setSecure(true);
+        cookie.setPath(path);
+        return cookie;
+    }
+
+    @Override
+    public void logout() {
+        // 删除 cookie 中的数据(或者是撤销 token)
+        // 删除 redis 中的 account login 数据
+        // 删除 redis 中的 session 数据
+        // 删除 SecurityContextHolder 中的数据
+
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        if (authentication instanceof AccountAuthToken) {
+            AccountAuthToken authToken = (AccountAuthToken) authentication;
+            int userId = authToken.getUserId();
+            String loginId = authToken.getLoginId();
+            clearCookie();
+
+            String userdata = String.format("%s:%s:%s", userId, 1, loginId);
+            deleteLoginData(userdata);
+
+            SecurityContext context = SecurityContextHolder.getContext();
+            context.setAuthentication(null);
+            SecurityContextHolder.clearContext();
+        }
     }
 
     @Override
-    public AccountAuthToken authByThirdParty(AccountAuthToken authToken) {
-        String errMsg = "接口未实现";
-        throw new DisabledException(errMsg);
+    public void clearCookie() {
+        String path = "/";
+        Cookie cookie2 = new Cookie(cookieName, null);
+        cookie2.setMaxAge(0);
+        cookie2.setDomain(domain);
+        cookie2.setSecure(true);
+        cookie2.setPath(path);
+        ServletUtil.getResponse().addCookie(cookie2);
+    }
+
+    private void deleteLoginData(String userdata) {
     }
 }

+ 42 - 39
manager/src/main/java/cn/reghao/devops/manager/account/service/impl/UserServiceImpl.java → manager/src/main/java/cn/reghao/devops/manager/account/service/impl/AccountServiceImpl.java

@@ -2,19 +2,23 @@ package cn.reghao.devops.manager.account.service.impl;
 
 import cn.reghao.devops.manager.account.db.repository.RoleRepository;
 import cn.reghao.devops.manager.account.db.repository.UserRepository;
-import cn.reghao.devops.manager.account.model.dto.UserCreateDto;
+import cn.reghao.devops.manager.account.model.dto.CreateAccountDto;
 import cn.reghao.devops.manager.account.model.po.Role;
-import cn.reghao.devops.manager.account.service.UserService;
+import cn.reghao.devops.manager.account.service.AccountService;
 import cn.reghao.jutil.jdk.security.Cryptor;
 import cn.reghao.jutil.jdk.security.Md5Cryptor;
 import cn.reghao.jutil.jdk.security.RandomString;
-import cn.reghao.devops.manager.account.model.dto.UserInfo;
-import cn.reghao.devops.manager.account.model.dto.UserRole;
+import cn.reghao.devops.manager.account.model.dto.AccountProfile;
+import cn.reghao.devops.manager.account.model.dto.AccountRole;
 import cn.reghao.devops.manager.account.model.po.User;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 
 import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -24,43 +28,43 @@ import java.util.stream.Collectors;
  */
 @Slf4j
 @Service
-public class UserServiceImpl implements UserService {
+public class AccountServiceImpl implements AccountService {
     private final UserRepository userRepository;
-    private RoleRepository roleRepository;
+    private final RoleRepository roleRepository;
     private final Cryptor cryptor;
+    private final PasswordEncoder passwordEncoder;
 
-    public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository) throws NoSuchAlgorithmException {
+    public AccountServiceImpl(UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder passwordEncoder) throws NoSuchAlgorithmException {
         this.userRepository = userRepository;
         this.roleRepository = roleRepository;
         this.cryptor = new Md5Cryptor();
+        this.passwordEncoder = passwordEncoder;
     }
 
     @Override
-    public User getUser(String username) {
-        User user = userRepository.findByUsername(username);
-        return user;
+    public void initAccount() {
+        List<User> list = userRepository.findAll(PageRequest.of(0, 1)).getContent();
+        if (list.isEmpty()) {
+            String username = RandomString.getString(3).toLowerCase(Locale.ROOT);
+            String password = RandomString.getString(10);
+            CreateAccountDto createAccountDto = new CreateAccountDto(username, password);
+            createAccount(createAccountDto);
+            log.info("初始化完成, 帐号和密码分别是 {} 和 {}", username, password);
+        }
     }
 
     @Override
-    public void createUser(UserCreateDto userCreateDto) {
-        String username = userCreateDto.getUsername();
-        User userEntity = userRepository.findByUsername(username);
-        if (userEntity != null) {
-            log.error("用户 {} 已存在", username);
-            return;
-        }
+    public void createAccount(CreateAccountDto createAccountDto) {
+        String username = createAccountDto.getUsername();
+        User user = userRepository.findByUsername(username);
+        if (user == null) {
+            String password = createAccountDto.getPassword();
+            String salt = RandomString.getSalt(64);
+            String encodedPasswd = passwordEncoder.encode(password + salt);
 
-        int roleId = userCreateDto.getRoleId();
-        Role role = roleRepository.findById(roleId).orElse(null);
-        if (role == null) {
-            log.error("角色 {} 不存在", roleId);
-            return;
+            user = new User(username, encodedPasswd, salt);
+            userRepository.save(user);
         }
-
-        String password = userCreateDto.getPassword();
-        User user = new User(username, password, Set.of(role.getTitle()));
-        setEncryptPassword(user);
-        userRepository.save(user);
     }
 
     private void setEncryptPassword(User user) {
@@ -73,7 +77,7 @@ public class UserServiceImpl implements UserService {
 
     // TODO 密码修改后是否应该清除用户 session?
     @Override
-    public void modifyUserPassword(Integer userId, String newPassword) {
+    public void updateAccountPassword(Integer userId, String newPassword) {
         User userEntity = userRepository.findById(userId).orElse(null);
         if (userEntity == null) {
             return;
@@ -85,33 +89,33 @@ public class UserServiceImpl implements UserService {
     }
 
     @Override
-    public void modifyUserInfo(UserInfo userInfo) {
-        User userEntity = userRepository.findById(userInfo.getUserId()).orElse(null);
+    public void updateAccountProfile(AccountProfile accountProfile) {
+        User userEntity = userRepository.findById(accountProfile.getUserId()).orElse(null);
         if (userEntity == null) {
             return;
         }
 
-        userEntity.setScreenName(userInfo.getScreenName());
-        userEntity.setMobile(userInfo.getMobile());
-        userEntity.setEmail(userInfo.getEmail());
+        userEntity.setScreenName(accountProfile.getScreenName());
+        userEntity.setMobile(accountProfile.getMobile());
+        userEntity.setEmail(accountProfile.getEmail());
         userRepository.save(userEntity);
     }
 
     @Override
-    public void setUserRoles(UserRole userRole) {
-        int userId = userRole.getUserId();
+    public void updateAccountRole(AccountRole accountRole) {
+        int userId = accountRole.getUserId();
         User userEntity = userRepository.findById(userId).orElse(null);
         if (userEntity == null) {
             return;
         }
 
-        Set<String> roles = userRole.getRoles().stream().map(Role::getTitle).collect(Collectors.toSet());
+        Set<String> roles = accountRole.getRoles().stream().map(Role::getTitle).collect(Collectors.toSet());
         userEntity.setRole(roles);
         userRepository.save(userEntity);
     }
 
     @Override
-    public void setUserStatus(Integer userId, Boolean enable) {
+    public void updateAccountStatus(Integer userId, Boolean enable) {
         User userEntity = userRepository.findById(userId).orElse(null);
         if (userEntity == null) {
             return;
@@ -121,9 +125,8 @@ public class UserServiceImpl implements UserService {
         userRepository.save(userEntity);
     }
 
-    // TODO 删除用户后还需清除用户 session
     @Override
-    public void deleteUser(Integer userId) {
+    public void deleteAccount(Integer userId) {
         User userEntity = userRepository.findById(userId).orElse(null);
         if (userEntity == null) {
             return;

+ 13 - 6
manager/src/main/java/cn/reghao/devops/manager/config/CacheConfig.java

@@ -21,16 +21,23 @@ public class CacheConfig {
     @Bean(name = "caffeineCacheManager")
     public CacheManager cacheManager() {
         CaffeineCacheManager cacheManager = new CaffeineCacheManager();
-        Caffeine<Object, Object> caffeineCache = caffeineCache();
+        Caffeine<Object, Object> caffeineCache = Caffeine.newBuilder()
+                .initialCapacity(1000)
+                .maximumSize(10_000)
+                .expireAfterAccess(365, TimeUnit.DAYS);;
         cacheManager.setCaffeine(caffeineCache);
         return cacheManager;
     }
 
-    @Bean("caffeineCache")
-    public Caffeine<Object, Object> caffeineCache() {
+    @Bean
+    public Cache<String, Object> caffeineCache() {
         return Caffeine.newBuilder()
-                .initialCapacity(1000)
-                .maximumSize(10_000)
-                .expireAfterAccess(365, TimeUnit.DAYS);
+                // 设置最后一次写入或访问后经过固定时间过期
+                .expireAfterWrite(30, TimeUnit.DAYS)
+                // 初始的缓存空间大小
+                .initialCapacity(10_000)
+                // 缓存的最大条数
+                .maximumSize(100_000)
+                .build();
     }
 }

+ 7 - 3
manager/src/main/java/cn/reghao/devops/manager/config/spring/AppLifecycle.java

@@ -1,6 +1,7 @@
 package cn.reghao.devops.manager.config.spring;
 
 import cn.reghao.devops.common.build.model.constant.CompileType;
+import cn.reghao.devops.manager.account.service.AccountService;
 import cn.reghao.devops.manager.app.db.repository.config.build.CompilerConfigRepository;
 import cn.reghao.devops.manager.app.model.po.config.build.CompilerConfig;
 import cn.reghao.devops.manager.app.service.config.BuildDirService;
@@ -33,30 +34,33 @@ public class AppLifecycle implements ApplicationRunner, DisposableBean {
     private final RoleRepository roleRepository;
     private final LogHandler logHandler;
     private final CompilerConfigRepository compilerConfigRepository;
+    private final AccountService accountService;
 
     public AppLifecycle(BuildDirService buildDirService, MachineService machineService, 
                         RoleRepository roleRepository, LogHandler logHandler,
-                        CompilerConfigRepository compilerConfigRepository) {
+                        CompilerConfigRepository compilerConfigRepository, AccountService accountService) {
         this.buildDirService = buildDirService;
         this.machineService = machineService;
         this.roleRepository = roleRepository;
         this.logHandler = logHandler;
         this.compilerConfigRepository = compilerConfigRepository;
+        this.accountService = accountService;
     }
 
     @Override
     public void run(ApplicationArguments args) {
+        accountService.initAccount();
         initLogConfig();
         initBuildDir();
         initRoles();
         checkCompilerConfig();
-        log.info("devops-manager 初始化完成");
+        log.info("devops-manager started");
     }
 
     @Override
     public void destroy() {
         machineService.flushToDataSource();
-        log.info("devops-manager 停止");
+        log.info("devops-manager shutdown...");
     }
 
     private void initLogConfig() {

+ 2 - 21
manager/src/test/java/AccountTest.java

@@ -1,6 +1,5 @@
 import cn.reghao.devops.manager.ManagerApplication;
-import cn.reghao.devops.manager.account.model.dto.UserCreateDto;
-import cn.reghao.devops.manager.account.service.UserService;
+import cn.reghao.devops.manager.account.service.AccountService;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -19,27 +18,9 @@ import org.springframework.test.context.junit4.SpringRunner;
 @RunWith(SpringRunner.class)
 public class AccountTest {
     @Autowired
-    UserService userService;
+    AccountService accountService;
 
     @Test
     public void createUserAccount() {
-        String username = "admin";
-        String password = "admin123456";
-        String screenName = "";
-        int roleId = 1;
-
-        UserCreateDto userCreateDto = new UserCreateDto();
-        userCreateDto.setUsername(username);
-        userCreateDto.setPassword(password);
-        userCreateDto.setScreenName(screenName);
-        userCreateDto.setRoleId(roleId);
-        //userService.createUser(userCreateDto);
-    }
-
-    @Test
-    public void updateUserPassword() {
-        int userId = 101;
-        String password = "admin123456";
-        userService.modifyUserPassword(userId, password);
     }
 }