Сначала вам нужно создать клиент, который будет использовать ваши остальные 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);
}
};
}
}
Вам необходимо создать DTO вашего ответа API входа в систему в Customer
объекте и подумать о том, как сохранить информацию всписок GrantedAuthority
Есть много других опций, которые вы можете использовать, но для меня это просто.
Редактировать: Вот только идея, как реализоватьGrantedAuthority для вашей аутентификации API:
Сначала вам нужен объект, который реализует интерфейс и хранит весь 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();
}
}
Извините за длинный пост, и я прошу прощения, если есть орфографические ошибки.Как я уже сказал, это только мое мнение, и есть много других решений.