@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user