Spring - Удаленная аутентификация Basi c - PullRequest
0 голосов
/ 10 апреля 2020

Я переписываю сервер Monolith Java / Spring для Microservices, предоставляя клиентам тот же API-интерфейс, чтобы они не заметили никаких изменений.

На сервере Monolith мы используем Spring-Security и Spring-Security-OAuth2.

Первая часть - создание API-шлюза на основе Java, который будет обрабатывать всю аутентификацию / авторизацию в качестве туннеля к серверу Monolith.

После создания нового микросервиса (используя spring initializr) Я попытался настроить Spring Security для туннелирования всей Аутентификации на Monolith Server, используя:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final AuthenticationProvider authenticationProvider;

    public WebSecurityConfig(AuthenticationProvider authenticationProvider) {
        this.authenticationProvider = authenticationProvider;
    }
}
@Component("authenticationProvider")
public class CustomRemoteAuthenticationProvider extends RemoteAuthenticationProvider {

    @Override
    @Autowired
    @Qualifier("remoteAuthenticationManager")
    public void setRemoteAuthenticationManager(RemoteAuthenticationManager remoteAuthenticationManager) {
        super.setRemoteAuthenticationManager(remoteAuthenticationManager);
    }

}
@Service("remoteAuthenticationManager")
public class CustomRemoteAuthenticationManager implements RemoteAuthenticationManager {

    @Override
    public Collection<? extends GrantedAuthority> attemptAuthentication(String username, String password) throws RemoteAuthenticationException {
        ... here I do an HTTP call to the Monolith `/oauth/login`
    }
}

Кажется, это работает, когда я посещаю страницу http://localhost:8080/login Spring-Security, я могу успешно войти в систему, и запрос направляется на наш сервер Monolith.

Проблема начинается, когда я пытаюсь настроить сервер ресурсов OAuth2, поскольку наши клиенты в настоящее время проходят проверку подлинности, используя POST для oauth/token с некоторыми базовыми данными c Аутентификация в заголовке:

Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Примечание: токен для базового c - это состояние * 1 041 * токен для всех клиентов (я знаю, что он ничего не стоит, но в настоящее время он реализован таким образом, и я пытаюсь реализовать полностью совместимый API-шлюз)

, который позволяет им взаимодействовать с этой конечной точкой и получить действительный токен для пользователя / пароля в теле (которое является application / x- www-form-urlencoded):

password=somepassword&username=user@example.com&grant_type=password&scope=read%20write

Проблема в том, что spring-security возвращает 401 Unauthorized для этого вызова даже без позволяя запросу войти в маршрут /oauth/login и выполнить удаленную аутентификацию.

Я не могу найти способ туннелировать аутентификацию Basi c на монолитный сервер, так что /oauth/login будет фактически аутентифицироваться против Монолит с удаленной базой c Аутентификация и после успеха он будет действовать как туннель и будет передавать само тело в конечную точку /oauth/login Монолита (как я успешно сделал в WebSecurityConfig выше)

Любой направление будет оценено. Заранее спасибо!

1 Ответ

0 голосов
/ 12 апреля 2020

Я выполняю аналогичный проект и думаю, что могу помочь вам с некоторыми рекомендациями.

OAuth2 - это авторизация и аутентификация безопасности на основе токенов, которые мы можем разбить на четыре компонента:

  1. Защищенный ресурс (доступ к нему может получить только аутентифицированный пользователь, имеющий соответствующую авторизацию)
  2. Владелец ресурса (определяет, какое приложение может вызывать свою службу, какому пользователю разрешен доступ к службе и что он может do)
  3. Приложение (приложение, которое будет вызывать службу от имени пользователей)
  4. Служба аутентификации OAuth2 (находится между приложением и защищенным ресурсом)

В вашем случае защищенный ресурс - это монолит, который вы хотите разрушить в архитектуре микросервисов.

  • Первое, что вам нужно сделать, это создать службу авторизации.

Создать проект SpringCloud из Spring Intilizr, убедитесь, что нижеприведенные зависимости присутствует:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

После этого в основной класс сервиса oauth2 необходимо добавить две аннотации. @EnableResourceServer используется, чтобы сообщить микросервису, что это защищенный ресурс. Я объясню ниже, зачем это нужно. @EnableAuthorizationServer сообщит Spring Cloud, что это сервис, который будет использоваться как OAuth2Service. Ниже приведен фрагмент кода:

@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
public class Oauth2ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(Oauth2ServerApplication.class, args);
    }

}

Мы создаем конечную точку, которая будет предоставлять информацию о пользователе. Эта конечная точка будет вызываться другими службами. По этой причине мы пометили это приложение @EnableResourceServer. Ниже расположена конечная точка отдыха, которая возвращает информацию о пользователе:

@RestController
@RequestMapping("/user")
public class UserRestController {

    @GetMapping(produces="application/json")
    public Map<String,Object> getUser(OAuth2Authentication user){
        Map<String,Object> userInfo = new HashMap<>();
        userInfo.put("user",user.getUserAuthentication().getPrincipal());
        userInfo.put("authorities", user.getUserAuthentication().getAuthorities());
        return userInfo;
    }

}

Теперь вы зарегистрируете приложение в сервисе oauth2. Вы определите приложение, которое будет обращаться к защищенному ресурсу. Вы создадите класс конфигурации, который определит, какое приложение может использовать ваш сервис.

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    OAuth2ConfigParameters oauth2ConfigParameters;

    @Bean
    public OAuth2ConfigParameters oAuth2ConfigParameters() {
        return new OAuth2ConfigParameters();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
        .withClient("your application")
        .secret("your password")
        .authorizedGrantTypes( "refresh_token","password","client_credentials")
        .scopes("webclient","mobileclient");
    }
}

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

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

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

    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

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

    @Override 
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("you user")
        .password(passwordEncoder().encode("your password"))
        .roles("your role");
    }
}

В конце уточните у почтальона, можете ли вы получить токен из службы oauth2.

HttpMethod : POST, URL : http://localhost: порт приложения / oauth / токен

Тип авторизации : Basi c, имя пользователя : клиент id, пароль : секрет клиента

Тело : данные формы,

грант: пароль

область действия: веб-клиент

имя пользователя: ваше имя пользователя

пароль: ваш пароль

После получения токена проверьте, можете ли вы получить доступ к этому токену по URL-адресу конечной точки, которой вы предоставляете информацию о пользователе.

HttpMethod : Получить, URL : localhost: порт приложения / пользователь

Авторизация : Носитель, Токен : генерируется токен


  • Во-вторых, защита вашего старого монолита, к которому будет обращаться сервер шлюза. Помните, что ваш старый монолит является защитой cted resource.

Сначала вам нужно добавить файлы Spring Security и OAuth2 в службу, которую вы пытаетесь защитить.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>

Далее в application.yml монолита, который мы настроить точку обслуживания вашего сервиса oauth2. Это сделано потому, что монолит является защищенной службой, и каждый раз, когда приходит запрос, вы хотите проверить, является ли токен запроса действительным.

security:
 oauth2:
  resource:
   userInfoUri: http://localhost:oauth2-app-port/auth/user

После этого не забудьте добавить @EnableResourceServer что делает монолит защищенным ресурсом.


@SpringBootApplication
@EnableResourceServer
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

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

@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
    }
}

  • Резюме

Ваш пользователь аутентифицирован из OAuth сервис и имеет сгенерированный токен. С созданным токеном отправьте запрос на монолит через сервер шлюза. Шлюз пытается получить доступ к монолиту, распространяя токен, полученный из запроса. Монолит проверяет, является ли токен действительным.

Ниже приведена связь моей микросервисной архитектуры с сервером шлюза zuul и сервером oauth2: https://github.com/rshtishi/payroll. Вы можете проверить это, если хотите увидеть больше деталей.

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