Обеспечение безопасности пружины, когда фасад защищен с помощью adal auth - PullRequest
2 голосов
/ 23 января 2020

Итак, у нас есть это приложение, которое состоит из двух частей:

  1. Интерфейс интерфейса пользователя - с использованием Angular JS
  2. Back end - остальные API, используя Spring boot

Внешний интерфейс защищен с помощью библиотеки microsoft-adal-angular6 для проверки подлинности с помощью Azure Active Directory

Мой вопрос заключается в том, как правильно защитить внутренний интерфейс, чтобы только пользователи, прошедшие проверку подлинности в активном каталоге, могли получить доступ к API?

1 Ответ

2 голосов
/ 29 января 2020

Я бы предложил использовать jwt токен , который прикрепляется к каждому запросу к вашему бэкэнду в качестве заголовка «Авторизация». Маркер состоит из трех частей: одна содержит данные о пользователе, а другая - подпись, поэтому вы можете проверить, что ваш токен был создан из надежного источника. Часть данных может выглядеть примерно так:

{
    "iss": "Online JWT Builder",
    "iat": 1580283510,
    "exp": 1611819510,
    "aud": "www.example.com",
    "sub": "jrocket@example.com",
    "GivenName": "Johnny",
    "roles": ["PROJECT_MANAGER", "ADMIN"]
    "scope": "WEBAPP"
}

Со стороны Spring я бы предложил использовать Spring Security 5 с последней конфигурацией. Вам понадобятся эти зависимости:

         <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>5.x.x.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
            <version>5.x.x.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
            <version>5.x.x.RELEASE</version>

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


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

    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    String jwkSetUri;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .cors().disable()
            .authorizeRequests()
            .antMatchers(("/webapp/**")).hasAuthority("SCOPE_WEBAPP")
            .antMatchers(("/admin/**")).hasRole("ADMIN")
            ...
            .and()
            .oauth2ResourceServer().jwt(jwtConfigurer -> jwtConfigurer.decoder(jwtDecoder())
            .jwtAuthenticationConverter(new CustomJwtAuthenticationConverter()))
            ...
        // @formatter:on
    }

    @Bean
    JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
    }
}

Мне пришлось использовать пользовательский JwtConverter для получения ролей из JWT, но это зависит от того, как вы это делаете, я думаю.

public class CustomJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {

    private final JwtGrantedAuthoritiesConverter defaultGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();

    public CustomJwtAuthenticationConverter() {
    }

    @Override
    public AbstractAuthenticationToken convert(@NotNull final Jwt jwt) {
        Collection<GrantedAuthority> authorities = Stream
                .concat(defaultGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream())
                .collect(Collectors.toSet());
        return new JwtAuthenticationToken(jwt, authorities);
    }

    private static Collection<? extends GrantedAuthority> extractResourceRoles(final Jwt jwt) {
        Collection<String> userRoles = jwt.getClaimAsStringList("roles");
        if (userRoles != null)
            return userRoles
                    .stream()
                    .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                    .collect(Collectors.toSet());
        return Collections.emptySet();
    }
}

Это позволяет вам защитить свое приложение на основе URL.

Роли в jwt, JwtConverter и аннотация @EnableGlobalMethodSecurity позволяет защитить даже на уровне метода .

@Transactional
@PreAuthorize("hasRole('ROLE_PROJECT_MANAGER')")
public Page<Project> findAll(Pageable pageable) {
    return projectRepository.findAll(pageable);
}

Azure Active Directory должна поддерживать jwt , но у меня нет опыта работы с этим IDP. Что я не могу ответить, так это то, как вы можете внедрить пользовательские утверждения, например роли, внутри токена и где получить jwks (Json Web Key Set), который используется для проверки подписи токена.

...