如何在Spring Security中绕过UsernamePasswordAuthentication

时间:2017-04-10 05:45:15

标签: spring authentication spring-boot spring-security jwt

我实现了一个接受JWT作为请求参数的API,并在身份验证时返回一个新的JWT。

@RequestMapping(value = "/authenticate/token", method = RequestMethod.POST,
    consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
    produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity authenticate(@RequestParam("login_token") final String token, HttpServletResponse response) {
    LOG.debug("Request to login with token : {}", token);
    try {
        String jwt = authService.loginByToken(token);
        response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
        return ResponseEntity.ok(new IdentityToken(jwt));
    } catch (AuthenticationException ae) {
        LOG.trace("Authentication exception trace: {}", ae);
        return new ResponseEntity<>(Collections.singletonMap("AuthenticationException",
            ae.getLocalizedMessage()), HttpStatus.UNAUTHORIZED);
    }
}

我的loginByToken实现如下所示

@Override public String loginByToken(String token) {
    if (!tokenProvider.validateToken(token)) {
        throw new BadCredentialsException("Token is invalid.");
    }
    SecureToken secureToken = tokenProvider.parseJwtToken(token);
    User user = userRepository.findByEmail(secureToken.getEmail());

    // TODO: Check Account Status is valid, User status is valid

    Calendar c = Calendar.getInstance();
    c.setTime(new Date());
    c.add(Calendar.DATE, Constants.PASSWORD_EXPIRY_DAYS);

    if (user.getPasswordExpiryDt() != null
        && user.getPasswordExpiryDt().after(c.getTime())) {
        throw new BadCredentialsException("Password changed");
    }

    // TODO: Find how to create authentication object and return ID token.
    // return tokenProvider.createToken(authentication, false);
    return token;
}

此时,我不确定如何创建一个身份验证对象,其中包含我可以传递给创建身份令牌的createToken函数的所有用户详细信息。

这是我的项目,没有这篇文章中提到的更改 - https://github.com/santoshkt/ngx-pipes-test

我已阅读有关匿名身份验证,PreAuthenticated等但不确定如何处理此案例。将不胜感激如何做到这一点。

2 个答案:

答案 0 :(得分:1)

如果您想使用Spring Security,您可能不应该使用Spring MVC端点来处理(预)身份验证。

在您的情况下,您可能希望更改Spring安全配置,以便它具有从请求参数中获取令牌的过滤器以及从令牌中检索用户/身份验证对象的身份验证提供程序:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .antMatcher("/authenticate/token")
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        // This is a filter bean you'll have to write
        .addFilterBefore(filter(), RequestHeaderAuthenticationFilter.class)
        // This is your token verifier/decoder
        .authenticationProvider(authenticationProvider())
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

对于过滤器,您可以从AbstractPreAuthenticatedProcessingFilter延伸并使其返回login_token参数。在这里,您必须实现两个方法getPreAuthenticatedPrincipal()getPreAuthenticatedCredentials()

@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
    // You could already decode your token here to return your username
    return request.getParameter("login_token");
}

@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
    return request.getParameter("login_token");
}

您的身份验证提供程序应为PreAuthenticatedAuthenticationProvider类型,此处您可以设置AuthenticationUserDetailsService

@Bean
public AuthenticationProvider authenticationProvider() {
    PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
    // service is a bean of type AuthenticationUserDetailsService
    // You could autowire this in your security configuration class
    provider.setPreAuthenticatedUserDetailsService(service);
    return provider;
}

现在,您可以创建自己的AuthenticationUserDetailsService以根据您的令牌检索UserDetails对象:

@Service
public class TokenAuthenticationUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

    @Override
    public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken authentication) throws UsernameNotFoundException {
        // In this case the authentication.getCredentials() will contain your token and you can return a UserDetails object
       return new User(/** ... */);
    }
}

答案 1 :(得分:0)

由于您要为JWT令牌请求提供HTML页面,最好的方法是创建自己的Spring Security Custom Entry Point 您可以查看示例here

如果是管理身份验证的另一个系统,并且您只想管理授权,则可以“信任”另一个系统,然后管理您自己的授权;在这种情况下,您可以使用here所述的PreAuthentication Scenario;你可以找到一个样本here

我希望它有用