Я делаю базовую аутентификацию при весенней загрузке. Также у меня есть фильтр, который выполняет фильтрацию заголовка и выдает ошибку, если я не передам необходимые значения в заголовке. Аутентификация и фильтрация заголовков работают нормально, если реализованы отдельно. Но если мы реализуем оба, я получаю одинаковый ответ для обеих проверок (фильтра и базовой аутентификации). Я предполагаю, что ответ фильтра генерируется первым, а позже заменяется ответом аутентификации.
PS: используется ** в приведенном ниже коде, чтобы указать местонахождение проблемы.
Любые эксперты, пожалуйста, совет. Спасибо
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE+2000)
@WebFilter
public class ValidTenantFilter extends OncePerRequestFilter {
@Autowired
private ClientRepository clientRepository;
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
AntPathMatcher pathMatcher = new AntPathMatcher();
return Constant.TENANT_FILTER_URL_LIST.stream()
.anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
log.info("Inside Tenant Checker filter for path {} with method {} ",request.getServletPath(),request.getMethod());
if(!this.isValidTenant(request)) {
** response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid "+ Constant.X_COMPANY_ID+" and/or "+Constant.X_OPERATOR_ID+ " are passed. Please validate the request."); **
}
else {
filterChain.doFilter(request, response);
}
}
private boolean isValidTenant(HttpServletRequest request) {
// Getting company id and operator id from the header , earlier we were using the tenant id
String companyId = request.getHeader(Constant.X_COMPANY_ID);
String operatorId=request.getHeader(Constant.X_OPERATOR_ID);
if(StringUtils.isNotEmpty(companyId) && StringUtils.isAlphanumeric(companyId)
&& StringUtils.isNotEmpty(operatorId) && StringUtils.isAlphanumeric(operatorId)) {
Client client = clientRepository.findByIdAndOperatorId(companyId, operatorId);
//Only active clients request are entertained. // PRODUCT FIX
if(client!=null && client.getId()!=null && client.isActive()) {
MDC.put(MDC_CLIENT_ID, client.getId().toString());
TenantContext.setCurrentTenant(client.getId().toString());
return true;
}
}
return false;
}
}
И ниже код для аутентификации:
@Configuration
@EnableWebSecurity
@Slf4j
public class SomeConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationEntryPointImpl authEntryPoint;
@Autowired
private ApplicationClients application;
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.csrf().disable()
.cors().disable();
//http.requiresChannel().antMatchers("/*").requiresSecure();
http.authorizeRequests()
// .antMatchers("/**").hasRole("ADMIN")
//.antMatchers("/user").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and().httpBasic();
http.headers().defaultsDisabled().cacheControl().and().contentTypeOptions()
.and().frameOptions().deny().xssProtection().block(false)
.and().httpStrictTransportSecurity().includeSubDomains(true).maxAgeInSeconds(31536000);
// Use AuthenticationEntryPoint to authenticate user/password
http.httpBasic().authenticationEntryPoint(authEntryPoint);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources",
"/swagger-resources/configuration/**", "/swagger-ui.html", "/webjars/**");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inMemoryUserDetailsManager());
}
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
log.info("Importing {} clients:", application.getClients().size());
application.getClients().forEach(client -> {
String encrytedPassword = this.passwordEncoder().encode(client.getPassword());
manager.createUser(User.withUsername(client.getUsername()).password(encrytedPassword).roles(client.getRoles()).build());
log.info("Imported client {}", client.toString());
});
return manager;
}
}
Код для точки входа аутентификации:
@Component
public class AuthenticationEntryPointImpl extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
//This is invoked when a user tries to access a secured REST resource without supplying any credentials
//We should just add a 401 Unauthorized response because there is no 'login page' to redirect to
** response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getOutputStream().println("{\"status\": " + HttpServletResponse.SC_UNAUTHORIZED + ", \"message\": \"" + authEx.getMessage() + "\" }");**
}
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("api-services");
super.afterPropertiesSet();
}
}
Получение ниже Ответа в POSTMAN:
1. Если я не передаю учетные данные почтальона, я получаю ответ ниже
{
«статус»: 401,
«message»: «Для доступа к этому ресурсу требуется полная аутентификация»
}
- Если я не передаю заголовки, в идеале я должен получить ответ ниже:
{
«отметка времени»: 1557753285553,
«статус»: 403,
«ошибка»: «Запрещено»,
"message": "Переданы неверные X-COMPANY-ID и / или X-OPERATOR-ID. Пожалуйста, подтвердите запрос.",
"путь": "/ apa / invoices"
}
Но вместо этого я получаю ошибку ниже:
- {
«статус»: 401,
«message»: «Для доступа к этому ресурсу требуется полная аутентификация»
}