首页 > 解决方案 > Spring Security 表单后认证

问题描述

我有一个可以通过表单发布请求访问的页面(移动应用程序的 webview 页面)。我的应用程序没有登录表单,但我需要保护它。移动应用程序将使用身份验证参数(例如(电子邮件/密码))调用此 web 视图页面。我需要使用给定的身份验证参数调用第三方 api 并确定它是否经过身份验证。我应该为我的场景使用哪种方法?

标签: spring-mvcspring-security

解决方案


如果可以在Authorization标头中传递身份验证参数,则可以在应用程序中启用 http 基本身份验证:

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();
    }

否则,您可以实现自己的安全过滤器,以从您的特定身份验证参数创建UsernamePasswordAuthenticationToken(或任何其他实现的类Authentication)实例并传递给AuthenticationManager; 但在另一个类的情况下,您需要通过覆盖该public boolean supports(Class<?> authentication)方法使下面的身份验证提供程序支持它。

然后实现一个自定义AuthenticationProvider,将身份验证委托给第三方 API,例如:

public class RestAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private static final String AUTH_URL = "http://third-party-service/authentication/basic";
    private RestTemplate restTemplate;

    public RestAuthenticationProvider() {
        this.restTemplate = new RestTemplate();
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            this.logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
        if (!authentication.getCredentials().toString().equals(userDetails.getPassword())) {
            this.logger.debug("Authentication failed: invalid credentials");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
        String password = authentication.getCredentials().toString();
        try {
            ResponseEntity<String> authenticationResponse = authenticate(username, password);
            if (authenticationResponse.getStatusCode().value() == 401) {
                throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
            }
            return createUser(authenticationResponse.getBody());
        } catch (BadCredentialsException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
        }
    }

    private ResponseEntity<String> authenticate(String username, String password) {
        HttpEntity entity = new HttpEntity(createHeaders(username, password));
        return restTemplate.exchange(AUTH_URL, HttpMethod.GET, entity, String.class);
    }

    private HttpHeaders createHeaders(String username, String password) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        String authorization = username + ":" + password;
        String basic = Base64.getEncoder().encodeToString(authorization.getBytes());
        headers.set("Authorization", "Basic " + basic);
        return headers;
    }

    private UserDetails createUser(String json) {
        return null; // TODO: Implement
    }
}

最后,让 Spring Security 使用您的提供程序:

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(new RestAuthenticationProvider())
                .eraseCredentials(false);
    }

推荐阅读