7

I'm trying the return the currently logged in user from my Spring Boot + AngularJS application, but SecurityContextHolder.getContext().getAuthentication() returns null.

Security config:

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("test").password("test").roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .formLogin().and()
            .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and()
            .authorizeRequests()
            .antMatchers("/index.html", "/login.html", "/").permitAll()
            .anyRequest().authenticated().and()
            .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
            .csrf().csrfTokenRepository(csrfTokenRepository());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/bower_components/**");
        web.ignoring().antMatchers("/js/**");
        web.ignoring().antMatchers("/css/**");
        web.ignoring().antMatchers("/api/user");
    }

    private static CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
}

Controller:

@RequestMapping(value="/user", method = RequestMethod.GET)
@ResponseBody
public User user() {
    User user = new User();
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null) {
        String name = auth.getName();
        user.setUsername(name);
    }
    return user;
}
user3170702
  • 1,971
  • 8
  • 25
  • 33

3 Answers3

12

Assuming that the controller you show is mapped to the context /api/user, then the reason is because you've added the line web.ignoring().antMatchers("/api/user"); to your security configuration, which means that all requests to that controller are not secured, and thus also don't have a SecurityContext. Remove that line, so that Spring Security secures it.

Excerpt from the Javadoc of the ignoring method:

Web Security provided by Spring Security (including the SecurityContext) will not be available on HttpServletRequest that match.

dunni
  • 43,386
  • 10
  • 104
  • 99
1

Another reason might be you've spun up another thread to the original one requesting the resource. That also happens when doing a parallelStream().foreach.

icyerasor
  • 4,973
  • 1
  • 43
  • 52
  • 1
    I was using a cron job that performs the tasks in different threads causing the SecurityContextHolder to return null each time. I handled it the other way. So, switching to another thread that requests the resource loses the SecurityContext... Thanks for the comment. – Niamatullah Bakhshi Apr 17 '22 at 05:25
0

If you want to get the Authentication object from a component class which is included in the Spring Security configuration you may use the following command.

Authentication auth = SecurityContextHolder.getContext().getAuthentication()

For all the other cases, if you want to get the Authentication object, you may get it using the HttpServletRequest which is available to any class in the Spring Context.

Object sc = request.getSession().getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
if (!(sc instanceof SecurityContext)) {
    // Something strange is happening
}
Authentication authentication = ((SecurityContext) sc).getAuthentication();
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92