refactor: 调整 Token 返回方式

Closes #1
This commit is contained in:
2026-01-05 23:53:31 +08:00
parent 8d148f88d0
commit 0a10c64278
9 changed files with 125 additions and 21 deletions
@@ -1,6 +1,7 @@
package com.onixbyte.helix.config; package com.onixbyte.helix.config;
import com.onixbyte.helix.properties.ApplicationProperties; import com.onixbyte.helix.properties.ApplicationProperties;
import com.onixbyte.helix.properties.AuthenticationProperties;
import com.onixbyte.helix.properties.MsalProperties; import com.onixbyte.helix.properties.MsalProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -18,11 +19,15 @@ import org.springframework.context.annotation.Configuration;
* application context. * application context.
* *
* @author zihluwang * @author zihluwang
* @since 1.0.0
* @see MsalProperties * @see MsalProperties
* @see EnableConfigurationProperties * @see EnableConfigurationProperties
* @since 1.0.0
*/ */
@Configuration @Configuration
@EnableConfigurationProperties({MsalProperties.class, ApplicationProperties.class}) @EnableConfigurationProperties({
MsalProperties.class,
AuthenticationProperties.class,
ApplicationProperties.class
})
public class AuthenticationConfig { public class AuthenticationConfig {
} }
@@ -1,11 +1,17 @@
package com.onixbyte.helix.controller; package com.onixbyte.helix.controller;
import com.onixbyte.helix.domain.web.request.LoginRequest; import com.onixbyte.helix.domain.web.request.LoginRequest;
import com.onixbyte.helix.domain.web.response.LoginSuccessResponse; import com.onixbyte.helix.domain.web.response.UserDetailResponse;
import com.onixbyte.helix.service.AuthService; import com.onixbyte.helix.service.AuthService;
import com.onixbyte.helix.service.TokenService;
import com.onixbyte.helix.service.UserService;
import com.onixbyte.helix.shared.TokenConstant;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -15,10 +21,18 @@ public class AuthController {
private static final Logger log = LoggerFactory.getLogger(AuthController.class); private static final Logger log = LoggerFactory.getLogger(AuthController.class);
private final AuthService authService; private final AuthService authService;
private final TokenService tokenService;
private final UserService userService;
@Autowired @Autowired
public AuthController(AuthService authService) { public AuthController(
AuthService authService,
TokenService tokenService,
UserService userService
) {
this.authService = authService; this.authService = authService;
this.tokenService = tokenService;
this.userService = userService;
} }
/** /**
@@ -28,10 +42,17 @@ public class AuthController {
* @return detailed user info and authentication token * @return detailed user info and authentication token
*/ */
@PostMapping("/login") @PostMapping("/login")
public LoginSuccessResponse loginWithUsernameAndPassword( public ResponseEntity<UserDetailResponse> loginWithUsernameAndPassword(
@Validated @RequestBody LoginRequest request @Validated @RequestBody LoginRequest request
) { ) {
return authService.login(request); var user = authService.login(request);
var token = tokenService.generateToken(user);
var cookie = authService.buildCookie(TokenConstant.TOKEN_NAME, token);
return ResponseEntity.status(HttpStatus.OK)
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.body(userService.getDetail(user));
} }
@GetMapping("/register-enabled") @GetMapping("/register-enabled")
@@ -1,20 +1,39 @@
package com.onixbyte.helix.manager; package com.onixbyte.helix.manager;
import com.onixbyte.helix.properties.ApplicationProperties; import com.onixbyte.helix.properties.ApplicationProperties;
import com.onixbyte.helix.properties.AuthenticationProperties;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Optional;
@Component @Component
public class ApplicationManager { public class ApplicationManager {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final AuthenticationProperties authenticationProperties;
@Autowired @Autowired
public ApplicationManager(ApplicationProperties applicationProperties) { public ApplicationManager(ApplicationProperties applicationProperties, AuthenticationProperties authenticationProperties) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.authenticationProperties = authenticationProperties;
} }
public String getDefaultEmail() { public String getDefaultEmail() {
return applicationProperties.defaultEmail(); return applicationProperties.defaultEmail();
} }
public String getExternalHost() {
return applicationProperties.externalHost();
}
public boolean isSslEnabled() {
return Optional.ofNullable(authenticationProperties.sslEnabled())
.orElse(false);
}
public boolean isSecureCookieEnabled() {
return Optional.ofNullable(authenticationProperties.secureCookieEnabled())
.orElse(false);
}
} }
@@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.bind.DefaultValue;
@ConfigurationProperties(prefix = "app.common") @ConfigurationProperties(prefix = "app.common")
public record ApplicationProperties( public record ApplicationProperties(
@DefaultValue("default@helix.onixbyte.dev") String defaultEmail @DefaultValue("default@helix.onixbyte.dev") String defaultEmail,
@DefaultValue("helix.onixbyte.dev") String externalHost
) { ) {
} }
@@ -0,0 +1,11 @@
package com.onixbyte.helix.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConfigurationProperties(prefix = "app.auth")
public record AuthenticationProperties(
@DefaultValue("true") Boolean sslEnabled,
@DefaultValue("true") Boolean secureCookieEnabled
) {
}
@@ -1,18 +1,17 @@
package com.onixbyte.helix.service; package com.onixbyte.helix.service;
import com.onixbyte.helix.client.TokenClient;
import com.onixbyte.helix.shared.SettingName;
import com.onixbyte.helix.domain.entity.Setting; import com.onixbyte.helix.domain.entity.Setting;
import com.onixbyte.helix.domain.entity.User;
import com.onixbyte.helix.domain.web.request.LoginRequest; import com.onixbyte.helix.domain.web.request.LoginRequest;
import com.onixbyte.helix.domain.web.response.LoginSuccessResponse;
import com.onixbyte.helix.exception.BizException; import com.onixbyte.helix.exception.BizException;
import com.onixbyte.helix.manager.CaptchaManager; import com.onixbyte.helix.manager.*;
import com.onixbyte.helix.manager.SettingManager;
import com.onixbyte.helix.security.authentication.UsernamePasswordAuthentication; import com.onixbyte.helix.security.authentication.UsernamePasswordAuthentication;
import com.onixbyte.helix.shared.SettingName;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -26,20 +25,20 @@ public class AuthService {
private final CaptchaManager captchaManager; private final CaptchaManager captchaManager;
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
private final TokenClient tokenClient;
private final SettingManager settingManager; private final SettingManager settingManager;
private final ApplicationManager applicationManager;
@Autowired @Autowired
public AuthService( public AuthService(
CaptchaManager captchaManager, CaptchaManager captchaManager,
AuthenticationManager authenticationManager, AuthenticationManager authenticationManager,
TokenClient tokenClient, SettingManager settingManager,
SettingManager settingManager ApplicationManager applicationManager
) { ) {
this.captchaManager = captchaManager; this.captchaManager = captchaManager;
this.authenticationManager = authenticationManager; this.authenticationManager = authenticationManager;
this.tokenClient = tokenClient;
this.settingManager = settingManager; this.settingManager = settingManager;
this.applicationManager = applicationManager;
} }
/** /**
@@ -49,7 +48,7 @@ public class AuthService {
* @return user information and user identity token * @return user information and user identity token
* @throws BizException if the user does not exist, or the username and password are incorrect * @throws BizException if the user does not exist, or the username and password are incorrect
*/ */
public LoginSuccessResponse login(LoginRequest request) { public User login(LoginRequest request) {
var captchaEnabled = Optional.ofNullable(settingManager.getSettingByName(SettingName.CAPTCHA_ENABLED)) var captchaEnabled = Optional.ofNullable(settingManager.getSettingByName(SettingName.CAPTCHA_ENABLED))
.map(Setting::asBoolean) .map(Setting::asBoolean)
.orElse(false); .orElse(false);
@@ -76,9 +75,7 @@ public class AuthService {
"Cannot perform login due to server crashes."); "Cannot perform login due to server crashes.");
} }
var token = tokenClient.generateToken(authentication.getDetails()); return authentication.getDetails();
return new LoginSuccessResponse(token, authentication.getDetails());
} }
/** /**
@@ -91,4 +88,17 @@ public class AuthService {
.map(Setting::asBoolean) .map(Setting::asBoolean)
.orElse(false); .orElse(false);
} }
public ResponseCookie buildCookie(String cookieName, String token) {
var cookieBuilder = ResponseCookie.from(cookieName, token)
.httpOnly(true)
.secure(applicationManager.isSslEnabled())
.path("/");
if (applicationManager.isSecureCookieEnabled()) {
cookieBuilder.domain(applicationManager.getExternalHost());
}
return cookieBuilder.build();
}
} }
@@ -0,0 +1,24 @@
package com.onixbyte.helix.service;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.onixbyte.helix.client.TokenClient;
import com.onixbyte.helix.domain.entity.User;
import org.springframework.stereotype.Service;
@Service
public class TokenService {
private final TokenClient tokenClient;
public TokenService(TokenClient tokenClient) {
this.tokenClient = tokenClient;
}
public String generateToken(User user) {
return tokenClient.generateToken(user);
}
public DecodedJWT verifyToken(String token) {
return tokenClient.verifyToken(token);
}
}
@@ -179,4 +179,15 @@ public class UserService {
userRoleManager.deleteByUserId(userId); userRoleManager.deleteByUserId(userId);
userManager.deleteById(userId); userManager.deleteById(userId);
} }
public UserDetailResponse getDetail(User user) {
var department = departmentManager.selectById(user.getDepartmentId());
var position = positionManager.selectById(user.getPositionId());
return UserDetailResponse.builder()
.user(user)
.departmentName(department.getName())
.positionName(position.getName())
.build();
}
} }
@@ -4,6 +4,8 @@ public final class TokenConstant {
public static final String TOKEN_HEADER_NAME = "Authorization"; public static final String TOKEN_HEADER_NAME = "Authorization";
public static final String TOKEN_NAME = "AccessToken";
public static final String TOKEN_PREFIX = "Bearer "; public static final String TOKEN_PREFIX = "Bearer ";
public static final int TOKEN_PREFIX_LENGTH = TOKEN_PREFIX.length(); public static final int TOKEN_PREFIX_LENGTH = TOKEN_PREFIX.length();