Spring Security использует значение переменной в классе для аутентификации

Я использую Spring Security в своем приложении. Я аутентифицирую API на основе роли (ADMIN, USER). Существует одна конечная точка API, к которой я хотел бы ограничить доступ, используя значение переменной, переданной ей в качестве параметра.

я имею

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

    httpSecurity.csrf().disable().exceptionHandling().authenticationEntryPoint(this.unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/api/**").authenticated()
            .anyRequest().permitAll();

    httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}

У меня звонок

@PostMapping("/something")
public ResponseEntity<BotResponse> handleRequest(@Valid @RequestBody SomeClass someClass) {
        // if someClass.getSomeValue() is not present in the User permissions, then it should give an unauthorized response.
        return value(someClass);
}

Пользователь в Spring Security - это:

public Class User {
    String userId;
    String userName;
    String authorities;
    List<String> someList;
    //Getters and setters for variables
}

И используется SomeClass:

public Class SomeClass {
    String someValue;
    String userName;
    ...
    // Getters and Setters
}

Как я не разрешаю пользователям на основе, если значение someClass.getSomeValue присутствует в someList пользователя?

2 ответа

Возможно, вы могли бы сделать такую ​​авторизацию с помощью глобального метода безопасности Spring.

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

@EnableGlobalMethodSecurity(prePostEnabled = true)

Тогда подать заявку @PreAuthorize используя Spring Expression Language, к вашей конечной точке. Что-то вроде..

@PostMapping("/something")
@PreAuthorize("@someService.checkUserAccess(principal, #someClass)")
public ResponseEntity<BotResponse> handleRequest(@Valid @RequestBody SomeClass someClass) {
        // if someClass.getSomeValue() is not present in the User permissions, then it should give an unauthorized response.
        return value(someClass);
}

@someService это bean-компонент, который вы бы автоматически подключали в Controller и определяли метод checkUserAccess() в этом файле. Что-то вроде..

public boolean checkUserAccess(Pricipal principal, SomeClass someClass) {
      // here you can fetch your full user object from db or session (depending on your application architecture)
      // apply what ever logic you want to apply, return true if user has access and false if no.
}

Примечание / предложение - Вы можете добавить это checkUserAccess() метод существующего пользовательского сервиса, если ваш дизайн приложения это позволяет, и автоматическое подключение пользовательского сервиса в контроллере.

Что касается вашего вопроса, один из подходов состоит в том, чтобы получить UserDetails, сохраненные в вашем контексте аутентификации Spring Security, а затем проверить соответствующие данные в этом объекте контекста по значению, переданному в качестве параметра. Я предполагаю, что у вас есть все необходимые значения, хранящиеся в контексте безопасности.
Эта проверка может быть выполнена в самом коде конечной точки (если у вас есть небольшое количество таких API). Если существует несколько API-интерфейсов, для которых требуется одна и та же логика, вам придется реализовать либо фильтр, который фильтрует только эти API-интерфейсы (config может быть записан в web.xml), либо pointcut(через AOP).

Другие вопросы по тегам