问题
In my usecase I don't have a User DB table to authenticate the user password. I am using HMAC signature which client sends in API request. On server side I calculate the same HMAC signature and just need to match them for successful authentication.
So I was thinking on using DaoAuthenticationProvider
which Spring Security provides, without writing own custom provider class.
Following are all the files I have. My Spring boot application does not build when I @Autowired private UserDetailsService userDetailsService
. Am I missing something?
RESTSecurityConfig
@Configuration
@EnableWebSecurity
@Order(1)
public class RESTSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService; // <---- build fails when I try to autowire
@Bean
public RESTSecurityFilter authenticationFilter() throws Exception {
RESTSecurityFilter authenticationFilter = new RESTSecurityFilter("/");
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
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;
}
}
RESTCredentials
public final class RESTCredentials {
private String requestSalt;
private String secureHash;
private RESTCredentials() {}
public RESTCredentials(String requestSalt, String secureHash) {
this.requestSalt = requestSalt;
this.secureHash = secureHash;
}
public String getRequestSalt() {
return requestSalt;
}
public String getSecureHash() {
return secureHash;
}
}
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);
}
}
Is there a simple and efficient way to Authenticate API in filter without the provider? I have "signature" and "hashSignature" both in filter so just want to compare them and return the API json response if both of them match.
Thanks
来源:https://stackoverflow.com/questions/64082698/spring-security-unable-to-autowire-userdetailsservice-in-daoauthenticationprov