feat: add local password login
parent
f017a153a3
commit
83c6fed1f9
@ -1,24 +0,0 @@
|
|||||||
package com.yau.digitalrmb.security.application;
|
|
||||||
|
|
||||||
import com.yau.digitalrmb.security.config.SecurityProperties;
|
|
||||||
import org.springframework.context.annotation.Profile;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Profile({"local", "test"})
|
|
||||||
public class BootstrapAdminAuthenticator {
|
|
||||||
private final SecurityProperties properties;
|
|
||||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
private final String passwordHash;
|
|
||||||
|
|
||||||
public BootstrapAdminAuthenticator(SecurityProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
this.passwordHash = passwordEncoder.encode(properties.getBootstrapAdmin().getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches(String username, String password) {
|
|
||||||
return properties.getBootstrapAdmin().getUsername().equals(username)
|
|
||||||
&& passwordEncoder.matches(password, passwordHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package com.yau.digitalrmb.security.application;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.yau.digitalrmb.identity.infrastructure.persistence.entity.PlatformUserSnapshotEntity;
|
||||||
|
import com.yau.digitalrmb.identity.infrastructure.persistence.entity.UserEntity;
|
||||||
|
import com.yau.digitalrmb.identity.infrastructure.persistence.mapper.PlatformUserSnapshotMapper;
|
||||||
|
import com.yau.digitalrmb.identity.infrastructure.persistence.mapper.UserMapper;
|
||||||
|
import com.yau.digitalrmb.shared.api.ErrorCode;
|
||||||
|
import com.yau.digitalrmb.shared.exception.BusinessException;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LocalAccountAuthenticationService {
|
||||||
|
private final UserMapper userMapper;
|
||||||
|
private final PlatformUserSnapshotMapper snapshotMapper;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final JwtTokenService jwtTokenService;
|
||||||
|
|
||||||
|
public LocalAccountAuthenticationService(UserMapper userMapper,
|
||||||
|
PlatformUserSnapshotMapper snapshotMapper,
|
||||||
|
PasswordEncoder passwordEncoder,
|
||||||
|
JwtTokenService jwtTokenService) {
|
||||||
|
this.userMapper = userMapper;
|
||||||
|
this.snapshotMapper = snapshotMapper;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
this.jwtTokenService = jwtTokenService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtTokenService.Token login(String username, String rawPassword) {
|
||||||
|
UserEntity user = userMapper.selectOne(new LambdaQueryWrapper<UserEntity>()
|
||||||
|
.eq(UserEntity::getUsername, username)
|
||||||
|
.eq(UserEntity::getEnabled, true)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
if (user == null || !passwordEncoder.matches(rawPassword, user.getPasswordHash())) {
|
||||||
|
throw invalidCredentials();
|
||||||
|
}
|
||||||
|
PlatformUserSnapshotEntity snapshot = snapshotMapper.selectById(user.getId());
|
||||||
|
if (snapshot == null) {
|
||||||
|
throw invalidCredentials();
|
||||||
|
}
|
||||||
|
return jwtTokenService.issueFor(user.getId(), snapshot.getAccount(), Set.of(snapshot.getRoleKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private BusinessException invalidCredentials() {
|
||||||
|
return new BusinessException(ErrorCode.UNAUTHORIZED, "用户名或密码错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package com.yau.digitalrmb.security.interfaces;
|
|
||||||
|
|
||||||
import com.yau.digitalrmb.security.application.BootstrapAdminAuthenticator;
|
|
||||||
import com.yau.digitalrmb.security.application.JwtTokenService;
|
|
||||||
import com.yau.digitalrmb.shared.api.ApiResponse;
|
|
||||||
import com.yau.digitalrmb.shared.api.ErrorCode;
|
|
||||||
import com.yau.digitalrmb.shared.exception.BusinessException;
|
|
||||||
import com.yau.digitalrmb.shared.web.TraceIdFilter;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
import org.springframework.context.annotation.Profile;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@Profile({"local", "test"})
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/v1/auth")
|
|
||||||
public class BootstrapLoginController {
|
|
||||||
private final BootstrapAdminAuthenticator authenticator;
|
|
||||||
private final JwtTokenService tokenService;
|
|
||||||
|
|
||||||
public BootstrapLoginController(BootstrapAdminAuthenticator authenticator, JwtTokenService tokenService) {
|
|
||||||
this.authenticator = authenticator;
|
|
||||||
this.tokenService = tokenService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/login")
|
|
||||||
public ApiResponse<LoginResponse> login(@Valid @RequestBody LoginRequest request) {
|
|
||||||
if (!authenticator.matches(request.username(), request.password())) {
|
|
||||||
throw new BusinessException(ErrorCode.UNAUTHORIZED, "用户名或密码错误");
|
|
||||||
}
|
|
||||||
JwtTokenService.Token token = tokenService.issueFor(request.username());
|
|
||||||
return ApiResponse.success(new LoginResponse(token.accessToken(), "Bearer", token.expiresIn()),
|
|
||||||
MDC.get(TraceIdFilter.MDC_KEY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue