Null @AuthenticationPrincipal и PreAuthorized не работает Spring Boot 2 / Security 5 - PullRequest
0 голосов
/ 11 мая 2018

У меня есть REST API и я хочу защитить его с помощью Spring Security. Я следовал за учебником здесь: https://github.com/Zuehlke/springboot-sec-tutor Весь мой проект можно найти здесь: https://github.com/YanickSchraner/wodss-tippspiel_backend

Проблема, с которой я сталкиваюсь, заключается в том, что @AuthenticationPrincipal возвращает Null даже после успешного выполнения POST-запроса входа в систему. Я предполагаю, что из-за этого аннотация @PreAuthorized тоже не работает.

Вот мой Конфигурация Безопасности:

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

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception{
        return super.authenticationManager();
    }

    @Bean
    public RESTAuthenticationFilter restAuthenticationFilter() {
        RESTAuthenticationFilter restAuthenticationFilter = new RESTAuthenticationFilter(objectMapper);
        restAuthenticationFilter.setAuthenticationManager(authenticationManager);
        restAuthenticationFilter.setAuthenticationSuccessHandler(restAuthenticationSuccessHandler);
        return restAuthenticationFilter;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and().exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
                .and().anonymous().disable()
                .csrf().disable() // CSRF protection is done with custom HTTP header (OWASP suggestion)
                .addFilterBefore(new XRequestedWithHeaderFilter(), CsrfFilter.class)
                .addFilterBefore(new EnforceCorsFilter(), CsrfFilter.class)
                .addFilterBefore(restAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .logout().logoutSuccessHandler((request, response, authentication) -> response.setStatus(HttpServletResponse.SC_OK))
                .and()
                .headers()
                .frameOptions().sameOrigin()
                .contentSecurityPolicy("default-src 'self'; script-src 'self' 'unsafe-inline'; report-uri /csp")
                .and()
                .httpStrictTransportSecurity()
                .maxAgeInSeconds(63072000);
        http
                .logout()
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .deleteCookies("BettingGame_SchranerOhmeZumbrunn_JSESSIONID");
        http
                .sessionManagement()
                .sessionFixation()
                .newSession();
    }
}

Вот мой UserDetailsServiceImpl:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;
    @Value("${security.login.errormessage}")
    private String errorMessage;

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findUserByNameEquals(username)
                .orElseThrow(() -> new UsernameNotFoundException(errorMessage));
        HashSet<GrantedAuthority> authorities = new HashSet<>();
        if(user.getRoles() != null){
            user.getRoles().stream()
                    .map(Role::getName)
                    .map(SimpleGrantedAuthority::new)
                    .forEach(authorities::add);
        }
        return new org.springframework.security.core.userdetails.User(user.getName(),user.getPassword(), authorities);
    }
}

Вот часть моего контроллера, где я получаю Null от @AuthenticationPricipal, а @PreAuthorized возвращает 403 даже после успешного входа в систему:

@RestController
@RequestMapping("/users")
//@PreAuthorize("hasRole('USER')")
public class UserController {

    private final UserService service;

    @RequestMapping(value = "/self",method = RequestMethod.GET)
    public ResponseEntity<User> getLogedInUser(@AuthenticationPrincipal User user){
        return new ResponseEntity<>(user, HttpStatus.OK);
    }

    @Autowired
    public UserController(UserService service) {
        this.service = service;
    }

    @GetMapping(produces = "application/json")
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<List<User>> getAllUsers() {
        return new ResponseEntity<>(service.getAllUsers(), HttpStatus.OK);
    }

1 Ответ

0 голосов
/ 11 мая 2018

Я наконец понял это. Две простые ошибки: 1. @AuthenticationPrinciple был Null, потому что я запрашивал объект User, но мой UserDetailsServiceImpl хранил / возвращал объект UserDetails. Сделав объект моего домена User реализующим интерфейс UserDetails, и заставив мой UserDetailServiceImpl возвращать этот объект User, эта проблема была исправлена.

  1. @ PreAuthorize ("hasRole ('USER')") вызывал 403, потому что spring префиксирует роли с помощью "ROLE_", и я сохранял свои роли без этого префикса в моей базе данных. Изменяя имя роли с «USER» на «ROLE_USER» в БД, эта проблема была исправлена.

Рабочий код можно найти в этом общедоступном проекте github: https://github.com/YanickSchraner/wodss-tippspiel_backend

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