使用Spring安全保护的Web应用程序中的REST用户身份验证

时间:2017-09-11 21:35:48

标签: java rest spring-security

我的基于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密钥。

有什么建议吗?

谢谢!

2 个答案:

答案 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