首先,大家好不要低估我的问题,因为我到处搜索过,但是找不到清晰的实现方式!但是仍然有些人不在乎并继续低估我的问题...
我正在开发一个Spring Boot应用,该应用根据端点登录API对用户进行身份验证,即: 我们通常会直接检查保存在数据库中的用户名和密码。但是这次的凭证是 在另一个程序员开发的Login端点API中。
我的Spring启动应用程序,需要针对该登录api的用户身份验证“登录表单”。在授予对应用程序的访问权限之前。换句话说,用户名和密码来自未保存在DB中的API!其他人已经开发的登录API。任何想法?我以前没有做过!登录API为:
POST: domain/authenticate/user
身体是:
{ "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,
}
}
答案 0 :(得分:2)
首先,您需要创建一个客户端以使用剩余的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的想法:
首先,您需要一个实现接口并存储整个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;
}
}
更好的解决方案是制造一个对象并将其作为对象存储,而不是作为字符串存储,而仅作为示例,它是一个字符串。
然后,您需要在访问身份验证api的代码中更改AuthenticationService
:
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();
}
}
很长的帖子,很抱歉,如果有拼写错误,我深表歉意。正如我所说的,这只是我的观点,还有许多其他解决方案。