首先,您需要创建一个客户端来消费您的 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<>();
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
列表中。
还有许多其他选项可供使用,但这对我来说是最简单的。
编辑:
这里只是实现你的认证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();
}
}
抱歉文章较长,如果有拼写错误我深感抱歉。正如我所说,这只是我的个人观点,还有许多其他解决方案。