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