我正在开发一个 Spring Boot 应用程序,该应用程序根据端点登录 API 对用户进行身份验证,即:
我们通常直接检查数据库中保存的用户名和密码。但是这次凭证是在另一个程序员开发的登录端点 API 中。
我的 Spring Boot 应用程序需要针对该登录 api 的用户身份验证“登录表单”。在授予对应用程序的访问权限之前。换句话说,用户名和密码来自未保存在数据库中的 API!那是别人已经开发的登录api。任何的想法?我以前没有这样做过!登录 API 是:
POST: domain/authenticate/user
body 是:{ "username" : "user",
"password" : "test"
}
回应是:{
"customer": {
"id": 62948,
"email": "test@test.com.au",
"givenName": "A",
"familyName": "OB",
"user": {
"id": 63158,
"version": 1,
"email": "adamo@test.com.au",
"password": "113b984921197350abfedb0a30f6e215beeda6c718e36559f48eae946664b405c77bc6bab222fe8d3191f82925921438b6566dda76613aa6cd4416e5d9ae51c8",
"givenName": "A",
"familyName": "OB",
},
"vehicles": [
{
"id": 79369,
"version": 0,
"country": "Australia"
},
"newState": null,
}
],
"fundingSources": [
{
"@class": "au.com.test.test",
"id": 54795,
"version": 0,
}
],
"citySuburb": null,
}
}
最佳答案
首先,您需要创建一个客户端来使用您的 rest api 进行身份验证:
@Service
public class AuthService {
@Bean
public RestTemplate authRestTemplate() {
return new RestTemplateBuilder().rootUri("http://domain/authenticate").build();
}
public Customer authenticate(MultiValueMap<String, String> request) {
return authRestTemplate().postForObject("/user", request, Customer.class);
}
public MultiValueMap<String, String> createRequest(String username, String password) {
MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
request.add("username", username);
request.add("password", password);
return request;
}
}
然后您必须创建一个组件或服务来使用该客户端:
@Service
public class AuthenticationService implements AuthenticationProvider {
private AuthService authService;
@Autowired
public void setAuthService(AuthService authService) {
this.authService = authService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
Customer customer = authService.authenticate(authService.createRequest(username, password));
if (customer != null) {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
//here you need to store your Customer object to use it anywhere while the user is logged in
// take a look on the edit
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities);
}
throw new AuthenticationServiceException("Invalid credentials.");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
最后,您需要使用自定义身份验证服务进行基本安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration implements WebMvcConfigurer {
private AuthenticationService authenticationService;
@Autowired
public void setAuthenticationService(AuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}
@Bean
public WebSecurityConfigurerAdapter webSecurityConfig() {
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.authenticationProvider(authenticationService);
}
};
}
}
您需要在
Customer
中创建登录 api 响应的 DTO对象并考虑如何将信息存储到 GrantedAuthority
的列表中您可以使用许多其他选项,但这对我来说很容易。
编辑:这里只是一个想法如何为您的身份验证 api 实现 GrantedAuthority:
首先,您需要一个实现接口(interface)并存储整个 json 的对象:
public class CustomerGrantedAuthority implements org.springframework.security.core.GrantedAuthority {
private String customerJson;
public CustomerGrantedAuthority(String customerJson){
this.customerJson = customerJson;
}
@Override
public String getAuthority() {
return customerJson;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomerGrantedAuthority that = (CustomerGrantedAuthority) o;
return java.util.Objects.equals(customerJson, that.customerJson);
}
@Override
public int hashCode() {
return java.util.Objects.hash(customerJson);
}
@Override
public String toString() {
return this.customerJson;
}
}
更好的解决方案是创建一个对象并将其存储为一个对象,而不是作为一个字符串,而只是为了示例它是一个字符串。
然后你需要更改
AuthenticationService
在您访问身份验证 api 的代码中:String customer = new RestTemplate().postForObject("http://domain/authenticate/user", createRequest(username, password), String.class);
if (customer != null) {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new CustomerGrantedAuthority(new ObjectMapper().writeValueAsString(customer)));
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities);
}
throw new AuthenticationServiceException("Invalid credentials.");
public MultiValueMap<String, String> createRequest(String username, String password) {
MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
request.add("username", username);
request.add("password", password);
return request;
}
这取决于您希望在应用程序中访问用户信息的位置和方式,但只是为了查看它是否有效,您可以使用简单的 RestController 进行测试,当用户登录时应该可以看到:
@RestController
public class TestController {
@GetMapping(value = "/auth")
public ResponseEntity getAuth() {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
CustomerGrantedAuthority customer = (CustomerGrantedAuthority) authorities.stream().findFirst().orElse(null);
return customer != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(customer.getAuthority()) : ResponseEntity.notFound().build();
}
}
对不起,很长的帖子,如果有拼写错误,我深表歉意。正如我所说,这只是我的意见,还有很多其他的解决方案。
关于spring - 使用 RESTful 登录 API 验证我的 Spring Boot 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55135304/