使用Spring Security-基于HMAC的自定义身份验证对所有API进行身份验证

问题描述

我正在尝试为我的微服务应用程序的所有REST API实现基于HMAC的身份验证(以了解有关HMAC refer this的更多信息)。我已经在Spring安全代码下面实现了,但是无法使该应用程序与Spring Security一起使用。

RESTSecurityConfig

@Configuration
@EnableWebSecurity
@Order(1)
public class RESTSecurityConfig extends WebSecurityConfigurerAdapter {

@Bean
public RESTSecurityFilter authenticationFilter() throws Exception {
    RESTSecurityFilter authenticationFilter = new RESTSecurityFilter("/");
    authenticationFilter.setAuthenticationManager(authenticationManagerBean());
    return authenticationFilter;
}

@Bean
public RESTAuthenticationProvider authenticationProvider() {
    RESTAuthenticationProvider provider = new RESTAuthenticationProvider();     
    return provider;
}

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) {
    auth.authenticationProvider(authenticationProvider());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().addFilterBefore(authenticationFilter(),UsernamePasswordAuthenticationFilter.class);
}
}

RESTSecurityFilter

public class RESTSecurityFilter extends AbstractAuthenticationProcessingFilter {

private static final Logger log = LoggerFactory.getLogger(RESTSecurityFilter.class);
private static final String ACCESS_KEY_ParaMETER_NAME = "x-access-key";
private static final String SIGNATURE_ParaMETER_NAME = "x-signature";
private static final String NONCE_ParaMETER_NAME = "x-nonce";
private static final String TIMESTAMP_ParaMETER_NAME = "x-timestamp";
private static final String SECRET_KEY = "xxxxxxxxxxxxxxxxx";

protected RESTSecurityFilter(String defaultFilterProcessesUrl) {
    super(defaultFilterProcessesUrl);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response)
        throws AuthenticationException,IOException,servletexception {
    String accessKey = getHeaderValue(request,ACCESS_KEY_ParaMETER_NAME);
    String signature = getHeaderValue(request,SIGNATURE_ParaMETER_NAME);
    String nonce = getHeaderValue(request,NONCE_ParaMETER_NAME);
    String timestamp = getHeaderValue(request,TIMESTAMP_ParaMETER_NAME);       
    String message = accessKey + ":" + nonce + ":" + timestamp;
    String hashSignature = null;
    try {
        hashSignature = HMacUtility.calculateHmac(message,SECRET_KEY);
        log.info("hashSignature : {}",hashSignature);
    }
    catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException e) {
        e.printstacktrace();
    }

    AbstractAuthenticationToken authRequest = createAuthenticationToken(accessKey,new RESTCredentials(signature,hashSignature));

    // Allow subclasses to set the "details" property
    setDetails(request,authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
}

@Override
protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication authResult) throws IOException,servletexception {
    super.successfulAuthentication(request,response,chain,authResult);
    chain.doFilter(request,response);
}

private String getHeaderValue(HttpServletRequest request,String headerParameterName) {
    return (request.getHeader(headerParameterName) != null) ? request.getHeader(headerParameterName) : "";
}

private AbstractAuthenticationToken createAuthenticationToken(String apikeyvalue,RESTCredentials restCredentials) {
    return new RESTAuthenticationToken(apikeyvalue,restCredentials);
}

protected void setDetails(HttpServletRequest request,AbstractAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

@Override
protected boolean requiresAuthentication(HttpServletRequest request,HttpServletResponse response) {
    return true;
}
}

RESTAuthenticationProvider

public class RESTAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

private static final Logger log = LoggerFactory.getLogger(RESTAuthenticationProvider.class);

@Autowired
private UserSecurityService userSecurityService;

@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

    RESTAuthenticationToken token = (RESTAuthenticationToken) authentication;
    if (token != null) {
        if (authentication.getCredentials() == null) {
            log.debug("Authentication Failed: no credentials provided");
            throw new BadCredentialsException(messages.getMessage("badCredentials","Bad credentials"));
        }
        RESTCredentials restCredentials = (RESTCredentials) authentication.getCredentials();

        log.info("==========userDetails.getpassword() = {}",userDetails.getpassword());
        log.info("=============restCredentials.getRequestSalt() = {}",restCredentials.getRequestSalt());
        log.info("=============restCredentials.getSecureHash() = {}",restCredentials.getSecureHash());

        // Check if signature and hashSignature matches and return API response
    } else {
        throw new AuthenticationCredentialsNotFoundException(
                messageformat.format("Expected Authentication Token object of type {0},but instead received {1}",RESTAuthenticationToken.class.getSimpleName(),authentication.getClass().getSimpleName()));
    }
}

@Override
protected UserDetails retrieveUser(String apiKey,UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException {
    log.info("Loading user by apikey = {}",apiKey);
    UserDetails loadedUser;
    try {
        loadedUser = userSecurityService.getUserByApiKey(apiKey);           
        log.info("########### Loaded user = {}",loadedUser);
    } catch (UsernameNotFoundException notFound) {
        throw notFound;
    }
    if (loadedUser == null) {
        throw new AuthenticationServiceException("UserSecurityServiceImpl returned null,which is an interface contract violation");
    }
    return loadedUser;
}
}

RESTAuthenticationToken

public class RESTAuthenticationToken extends UsernamePasswordAuthenticationToken {
private static final long serialVersionUID = 1L;

public RESTAuthenticationToken(Object principal,Object credentials) {
    super(principal,credentials);
}

public RESTAuthenticationToken(Object principal,Object credentials,Collection<? extends GrantedAuthority> authorities) {
    super(principal,credentials,authorities);
}
}

UserSecurityRepository

public interface UserSecurityRepository {
    UserDetails getUserByUsername(String username);
    UserDetails getUserByApiKey(String apiKey);
}

UserSecurityService

@Service
public interface UserSecurityService extends UserDetailsService {
    UserDetails getUserByApiKey(String apiKey);
}

有没有提供程序的简单有效的方法来在过滤器中对API进行身份验证吗?我已经在过滤器中向用户发送了“签名”和“ hashSignature”,所以只想比较它们,如果两者匹配则返回API json响应。

非常感谢您的帮助!谢谢

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)