我的基于Spring Boot的Web应用程序针对远程REST API进行身份验证。为此,我已经扩展AbstractUserDetailsAuthenticationProvider
,如此:
public class RestAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// TODO Auto-generated method stub
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
String password = (String) authentication.getCredentials();
Credentials creds = new Credentials();
creds.setUsername(username);
creds.setPassword(password);
RestTemplate template = new RestTemplate();
try {
ResponseEntity<Authentication> auth = template.postForEntity("http://localhost:8080/api/authenticate",
creds, Authentication.class);
if (auth.getStatusCode() == HttpStatus.OK) {
String token = auth.getHeaders().get("Authorization").get(0); // Great! Now what?
return new User(authentication.getName(), password,
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
}
throw new BadCredentialsException("Failed to authenticate, server returned " + auth.getStatusCodeValue());
} catch (HttpClientErrorException e) { // Check for type of error
throw new BadCredentialsException(e.getStatusText());
}
}
}
这很有效。但是我的问题是,后续访问API将需要在RestTemplate
标头中提供API密钥。这是
line:
String token = auth.getHeaders().get("Authorization").get(0); // Great! Now what?
我所追求的是在会话级别持久保存该令牌以供将来访问的一些方法。在线下,我正在努力做一些事情:
SecurityContext context = SecurityContextHolder.getContext();
Authentication userDetails = context.getAuthentication() ;
以某种方式userDetails
将包含API密钥。
有什么建议吗?
谢谢!
答案 0 :(得分:0)
你设计&amp;实施自己的安全解决方案。该框架为您提供了一种基于凭据来实施解决UserDetails
的方法。
我看到后续调用此问题的问题。出于这个原因,“旧学校”网络应用程序有会话,但“新学校”认为它“不酷”,因为它“不扩展”(或其他任何原因),我认为你是其中之一。
如果您不想使用会话 - 那么您需要根据已识别的内容从数据库(或缓存,会话存储或您喜欢的内容)中获取您的用户。
您的当前实施通过使用用户名和密码提供此功能,但我认为您不希望将其保留在内存和放大器中;随每个请求发送。
因此,您希望生成令牌,将其存储在数据库(或缓存,或令牌存储或会话存储)中,然后实现另一个AuthenticationProvider
,这将在下次读取基于UserDetails
的{{1}}令牌,而不是用户凭证。
您可以使用JWT
令牌,该令牌实际上可以将您的整个UserDetails
对象序列化为令牌本身&amp;通过网络发送它,但我不建议这样做,因为没有办法使它无效,除非您将令牌id
存储在数据库/会话存储中。
更多内容请点击此处:Invalidating JSON Web Tokens
答案 1 :(得分:0)
事实证明,扩展WebJob
就像这样简单:
WebAuthenticationDetails
然后在我的public class JwtAuthenticationDetails extends WebAuthenticationDetails {
private static final long serialVersionUID = 6951476359238150556L;
private String token ;
public JwtAuthenticationDetails(HttpServletRequest request) {
super(request);
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
@Override
public String toString() {
return "JwtAuthenticationDetails [token=" + token + "; " + super.toString() + "]";
}
}
注册:
WebSecurityConfigurerAdapter
最后,
在我的private AuthenticationDetailsSource<HttpServletRequest, JwtAuthenticationDetails> getAuthenticationDetailsSource() {
// TODO Auto-generated method stub
return new AuthenticationDetailsSource<HttpServletRequest, JwtAuthenticationDetails>() {
@Override
public JwtAuthenticationDetails buildDetails(HttpServletRequest context) {
return new JwtAuthenticationDetails(context);
}
} ;
}
中,我可以将令牌存储在身份验证详细信息中:
RestAuthenticationProvider