I've created a form that sends the data to my backend, which persists it into the database 
This works well as long as I have .permitAll() on my antMatcher, but when I try to secure it so that only admins can make that call (admin role in the DB is ROLE_ADMIN), it returns a 401 Unauthorized Access with no message. I've tried
- .hasRole("ADMIN")
- .hasRole("ROLE_ADMIN")
- .hasAuthority("ADMIN")
- .hasAuthority("ROLE_ADMIN")
My request looks like this (posting for the headers):
My SecurityConfig class:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity( securedEnabled = true, jsr250Enabled = true, prePostEnabled = true ) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsServiceImpl userDetailsService; @Autowired private JwtAuthenticationEntryPoint unauthorizedHandler; @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean(BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http .cors() .and() .csrf() .disable() .exceptionHandling() .authenticationEntryPoint(unauthorizedHandler) .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/", "/favicon.ico", "/**/*.png", "/**/*.gif", "/**/*.svg", "/**/*.jpg", "/**/*.html", "/**/*.css", "/**/*.js") .permitAll() .antMatchers("/api/auth/**") .permitAll() .antMatchers("/api/book/**") .permitAll() .antMatchers("/api/author/**") // .permitAll() .hasAnyRole("ROLE_ADMIN", "ADMIN", "ROLE_USER", "USER", "ROLE_ROLE_ADMIN", "ROLE_ROLE_USER") .anyRequest() .authenticated(); http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } } My UserDetailsServiceImpl class:
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired UserRepository userRepository; @Override @Transactional public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email); return UserDetailsImpl.create(user); } @Transactional public UserDetails loadUserById(Integer id) { User user = userRepository.findById(id).orElseThrow( () -> new UsernameNotFoundException("User not found with id: " + id) ); return UserDetailsImpl.create(user); } } My JwtAuthenticationEntryPoint class:
@Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class); @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { logger.error("Unauthorized access. Message:", e.getMessage()); httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); } } My JwtAuthenticationFilter:
public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtTokenProvider tokenProvider; @Autowired private UserDetailsServiceImpl userDetailsService; private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { try { String jwt = getJwtFromRequest(httpServletRequest); if(StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { Integer userId = tokenProvider.getUserIdFromJWT(jwt); UserDetails userDetails = userDetailsService.loadUserById(userId); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest)); } } catch (Exception e) { logger.error("Could not set user authentication in security context", e); } filterChain.doFilter(httpServletRequest, httpServletResponse); } private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7, bearerToken.length()); } return null; } } The JWT Token's validity is properly checked. That's not the issue at hand. Any help is appreciated.
EDIT: Added implementation of UserDetailsImpl:
public class UserDetailsImpl implements UserDetails { private Integer id; @JsonIgnore private String email; private String name; @JsonIgnore private String password; private boolean isAdmin; private Collection<? extends GrantedAuthority> authorities; public UserDetailsImpl(Integer id, String email, String name, String password, boolean isAdmin, Collection<? extends GrantedAuthority> authorities) { this.id = id; this.name = name; this.email = email; this.password = password; this.authorities = authorities; this.isAdmin = isAdmin; } public static UserDetailsImpl create(User user) { List<GrantedAuthority> authorities = user.getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getName().name()) ).collect(Collectors.toList()); boolean isAdmin = false; for(Role role: user.getRoles()) { if(RoleName.ROLE_ADMIN.equals(role.getName())) { isAdmin = true; } } return new UserDetailsImpl( user.getId(), user.getEmail(), user.getName(), user.getPassword(), isAdmin, authorities ); } public Integer getId() { return id; } public String getName() { return name; } @Override public String getUsername() { return email; } @Override public String getPassword() { return password; } public boolean isAdmin() { return isAdmin; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserDetailsImpl that = (UserDetailsImpl) o; return Objects.equals(id, that.id); } @Override public int hashCode() { return Objects.hash(id); } Added this to check if the authorities are present after UserDetailsImpl.create(user) call: 
Output:
Login part of the AuthenticationController:





userDetails.getAuthorities()is?