Spring boot предоставляет оставшийся API отдыха с аутентификацией basi c, используя идентификатор клиента и пароль клиента - PullRequest
1 голос
/ 01 апреля 2020

В моем приложении у меня есть как отдых, так и веб-часть. Веб-часть имеет шаблон URL /admin/**, который использует аутентификацию на основе форм. в то время как остальная часть имеет шаблон URL /api/**, который использует токен jwt для аутентификации. Также по умолчанию в конфигурации есть другой шаблон URL /oauth/* ie /oauth/token , /oauth/token_key etc Я пытаюсь выставить остальные API конкретно /open/api/**, который использует Basi c Auth, как в /oauth/token. Так что любой запрос на /open/api/** выглядит как

POST http://{{host}}/open/api/test
  Accept: application/json
  Authorization: Basic {base64encoded(clientId:clientSecret)} // this is important to expose the api
  cache-control: no-cache

Я пробовал Google, я не мог найти конфигурацию для него. Моя конфигурация


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MultiHttpSecurityConfig {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Configuration
    @Order(1)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        Logger logger = LoggerFactory.getLogger(FormLoginWebSecurityConfigurerAdapter.class);

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                .antMatcher("/admin/**")
                .authorizeRequests()
                    .anyRequest().hasAnyAuthority("ADMIN_USER")
                .and()
                    .formLogin()
                    .loginPage("/admin/login")
                    .permitAll()
                .and()
                    .logout()
                        .logoutUrl("/admin/logout")
                        .invalidateHttpSession(true)
                        .permitAll()
                .and()
                        .exceptionHandling()
                        .accessDeniedPage("/403");

            http.csrf().disable();

            http.headers().frameOptions().disable();

        }

        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

    }

    @Configuration
    @EnableResourceServer
    @Order(2)
    public class CustomResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {

        Logger logger = LoggerFactory.getLogger(CustomResourceServerConfigurerAdapter.class);

        @Autowired
        private JdbcTemplate jdbcTemplate;

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(jdbcTemplate.getDataSource());
        }

        @Bean
        @Primary
        //Making this primary to avoid any accidental duplication with another token service instance of the same name
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setTokenStore(tokenStore());
            defaultTokenServices.setSupportRefreshToken(true);
            return defaultTokenServices;
        }



        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenServices(tokenServices());
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {

            http
                .antMatcher("/api/**")
                .authorizeRequests()
                    .antMatchers("/api/**" ).authenticated();

        }
    }

}

Есть ли способ настроить /open/api в этой конфигурации или мне нужно написать собственную реализацию для этого?

РЕДАКТИРОВАТЬ ... .

После долгих попыток придумал добавить фильтр, как показано ниже. Это работает, но я не знаю, правильно ли это делать. Предложения приветствуются.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.stereotype.Component;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class OpenApiFilter implements Filter {

    Logger logger = LoggerFactory.getLogger(OpenApiFilter.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ClientDetailsServiceConfigurer clients;

    @Autowired
    private PasswordEncoder encoder;

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        logger.info("Initializing filter :{}", this);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

                HttpServletRequest req = (HttpServletRequest) request;
                HttpServletResponse httpResponse = (HttpServletResponse) response;

                String auth = req.getHeader(HttpHeaders.AUTHORIZATION);

                if(auth == null ){

                    httpResponse.setContentType("application/json");
                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

                    return;

                }else{

                    if(!auth.startsWith("Basic ")){

                        httpResponse.setContentType("application/json");
                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

                        return;

                    }else{

                        auth = auth.substring("Basic ".length());
                        if(!Base64.isBase64(auth)){

                            httpResponse.setContentType("application/json");
                            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

                            return;

                        }else{

                            byte[] decoded = Base64.decodeBase64(auth);
                            auth = new String(decoded, "UTF-8");

                            if( !(auth.indexOf(":") > 1) ){

                                httpResponse.setContentType("application/json");
                                httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

                                return;

                            }else{

                                String[] credentials = auth.split(":");

                                try {

                                    ClientDetailsService jdbcClientDetailsServiceBuilder = clients.jdbc(jdbcTemplate.getDataSource()).build();

                                    ClientDetails clientDetails =  jdbcClientDetailsServiceBuilder.loadClientByClientId(credentials[0]);

                                    if(!encoder.matches(credentials[1], clientDetails.getClientSecret())){

                                        httpResponse.setContentType("application/json");
                                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");   

                                        return;

                                    }

                                } catch (Exception e) {

                                    logger.error("{}", e.getMessage());

                                    httpResponse.setContentType("application/json");
                                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

                                    return;
                                }

                            }

                        }

                    }

                }

                chain.doFilter(request, response);

    }

    @Override
    public void destroy() {
        logger.info("Destructing filter :{}", this);
    }
}

И зарегистрированы с бобом

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

@Configuration
public class OpenApiFilterConfig {

    @Autowired
    private OpenApiFilter openApiFilter;

    @Bean
    public FilterRegistrationBean < OpenApiFilter > filterRegistrationBean() {
     FilterRegistrationBean < OpenApiFilter > registrationBean = new FilterRegistrationBean<>();

     registrationBean.setFilter(openApiFilter);
     registrationBean.addUrlPatterns("/open/api/*");
     registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); //set precedence
     return registrationBean;

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...