Не удается получить роли, работающие в Spring Boot Security - PullRequest
0 голосов
/ 02 февраля 2020

Я потратил несколько дней, пытаясь заставить РОЛИ работать в Spring Security с использованием токенов JWT . Кажется, аутентификация работает нормально, но авторизация , похоже, все еще не работает.

Моя текущая настройка заключается в том, что у меня есть ...

  • База данных в памяти для Пользователи (у меня есть один единственный пользователь с именем «лев» и одна роль «KING»)
  • конечная точка аутентификации, которая аутентифицирует пользователя и возвращает JWT в ответе.

My WebCofig выглядит следующим образом:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/hello").permitAll()
            .antMatchers("/authenticate").permitAll()
            .anyRequest().authenticated()
        .and().exceptionHandling()
        .and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}

Я хочу сказать, что

  • каждый может получить доступ (/)
  • любой может получить доступ к "hello" и "authenticate"

Мой веб-контроллер выглядит следующим образом:

@Controller
public class WebController {  

    @PreAuthorize("permitAll()")  
    @RequestMapping("/hello")  
    @ResponseBody  
    public String hello() {  
        return "Hello! ALL USERS logged in or not are allowed to see this!";  
    }  

    @PreAuthorize("hasRole('KING')")
    @RequestMapping("/king")  
    @ResponseBody  
    public String king() {  
        return "Hello King";  
    } 

    @PreAuthorize("hasRole('ROLE_KING')")
    @RequestMapping("/king2")  
    @ResponseBody  
    public String king2() {  
        return "Hello King2";  
    } 
}

Мой веб-токен, возвращенный через мою аутентификацию, выглядит хорошо (я думаю ..). Декодированное тело выглядит так:

{
  "sub": "lion",
  "scopes": "KING",
  "iat": 1580645802,
  "exp": 1580663802
}

... и позволит мне получить доступ куда угодно, где мне просто нужно пройти аутентификацию. "anyRequest (). authenticated ()".

Однако конечные точки REST king и king2 дают мне 403 - "Отказано в доступе" , даже если у моего пользователя есть роль KING (Я пробовал и KING, и ROLE_KING)

Мне кажется, что мне не хватает части головоломки.

Мой JWT-фильтр тоже выглядит неплохо. Объект аутентификации (.. который устанавливается в обработчике контекста безопасности, например, так: SecurityContextHolder.getContext (). SetAuthentication (аутентификация);) имеет ровно ОДИН SimpleGrantedAuthority с ролью = KING.

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {

    final String authorizationHeader = request.getHeader("Authorization");

    String username = null;
    String jwt = null;

    if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
        jwt = authorizationHeader.substring(7);

        username = jwtUtil.extractUsername(jwt);
    }

    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        if (jwtUtil.validateToken(jwt, userDetails)) {

            userDetails.getAuthorities(); //has exactly ONE SimpleGrantedAuthority with value "KING"

            SimpleGrantedAuthority s = new SimpleGrantedAuthority("asfd");

            s.getAuthority(); //string


            UsernamePasswordAuthenticationToken authentication = jwtUtil.getAuthentication(jwt,
                    SecurityContextHolder.getContext().getAuthentication(), userDetails);

            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            logger.info("authenticated user " + username + ", setting security context");
            SecurityContextHolder.getContext().setAuthentication(authentication);

        }
    }

    chain.doFilter(request, response);
}

Мой UserDetailsService выглядит вот так:

public class UserService implements UserDetailsService {

    @Autowired
    private UserRepository repository;

    @Autowired
    private PasswordValidationService passwordValidationService;

    @Override
    public User loadUserByUsername(String userName) throws UsernameNotFoundException {

        UserEntity u = repository.findByUserNameIgnoreCase(userName);

        SimpleGrantedAuthority a = new SimpleGrantedAuthority(u.getRole().toString());

        ArrayList<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        auths.add(a);

        return new User(u.getUserName(), u.getPassword(), auths);
    }
}

Все выглядит хорошо для меня, поэтому я сейчас растерялся: (

*********** ОБНОВЛЕНИЕ ***** *******

Если я использую hasAuthority вместо hasRole , тогда это работает:

@PreAuthorize("hasAuthority('KING')")
@RequestMapping("/king3")  
@ResponseBody  
public String king3() {  
    return "Hello King";  
} 

Так как мне получить hasRole для работы? Я пропускаю добавление "ROLE_" где-то в моем коде?

...