Rest Null@AuthenticationPrincipal且预授权无效Spring Boot 2/Security 5

Rest Null@AuthenticationPrincipal且预授权无效Spring Boot 2/Security 5,rest,spring-boot,spring-security,Rest,Spring Boot,Spring Security,我有一个RESTAPI,希望用Spring安全性来保护它。我在这里遵循了教程: 我的整个项目可以在这里找到: 我面临的问题是,@AuthenticationPrincipal即使在执行成功的登录POST请求后仍返回Null。我认为,正因为如此,@PreAuthorized注释也无法工作 这是我的安全配置: @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public clas

我有一个RESTAPI,希望用Spring安全性来保护它。我在这里遵循了教程: 我的整个项目可以在这里找到:

我面临的问题是,@AuthenticationPrincipal即使在执行成功的登录POST请求后仍返回Null。我认为,正因为如此,@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);
    }
}
@服务
公共类UserDetailsServiceImpl实现UserDetailsService{
@自动连线
私有用户存储库用户存储库;
@值(${security.login.errormessage}”)
私有字符串错误消息;
@凌驾
@事务(只读=真)
public UserDetails loadUserByUsername(字符串用户名)引发UsernameNotFoundException{
User=userRepository.finduserbynamequals(用户名)
.orelsetrow(()->新用户名NotFoundException(errorMessage));
HashSet authorities=新HashSet();
if(user.getRoles()!=null){
user.getRoles().stream()
.map(角色::getName)
.map(SimpleGrantedAuthority::新建)
.forEach(当局::添加);
}
返回新的org.springframework.security.core.userdetails.User(User.getName(),User.getPassword(),authorities);
}
}
这里是我的控制器的一部分,我从@AuthenticationPricipal获得Null,@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);
    }
@RestController
@请求映射(“/users”)
//@预授权(“hasRole('USER')”)
公共类用户控制器{
私人最终用户服务;
@RequestMapping(value=“/self”,method=RequestMethod.GET)
公共响应属性getLogedInUser(@AuthenticationPrincipal User){
返回新的响应属性(用户,HttpStatus.OK);
}
@自动连线
公共用户控制器(用户服务){
服务=服务;
}
@GetMapping(products=“application/json”)
@预授权(“hasRole('USER')”)
公众反应{
返回新的响应属性(service.getAllUsers(),HttpStatus.OK);
}

我终于明白了。两个简单的错误: 1.@AuthenticationPrinciple为Null,因为我请求一个用户对象,但我的UserDetailsServiceImpl正在存储/返回一个UserDetails对象。通过使我的用户域对象实现UserDetails接口并使我的UserDetailsServiceImpl返回该用户对象,此isseue已修复

  • @预授权(“hasRole('USER'))导致403错误,因为spring在角色前面加了“ROLE_”,我在数据库中存储了没有该前缀的角色。通过将数据库中的角色名称从“USER”更改为“ROLE_USER”,此问题得到了解决
  • 可在此公共github项目中找到工作代码: