«Для доступа к этому ресурсу требуется полная аутентификация» даже при передаче действующего токена JWT.JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 «Для доступа к этому ресурсу требуется полная аутентификация» даже при передаче действующего токена JWT.

Сообщение Anonymous »

До сих пор я в основном работал с C# и ASP.NET, но теперь мне нужно написать веб-API на Java Spring. Я совершенно новичок в этой среде и не могу справиться с аутентификацией токена JWT, для меня это выглядит как черная магия. Если я открываю конечную точку для анонимного пользователя, они работают нормально, но когда я пытаюсь потребовать аутентификацию, я всегда получаю код состояния 401 Unauthorized, даже если я передаю действительный токен JWT в своем запросе. Это мой класс конфигурации безопасности:

Код: Выделить всё

@Configuration
@EnableWebSecurity
public class SecurityConfig {

private final JwtAuthEntryPoint authEntryPoint;
private final UserDetailsServiceImpl userDetailsService;

@Autowired
public SecurityConfig(JwtAuthEntryPoint authEntryPoint, UserDetailsServiceImpl userDetailsService) {
this.authEntryPoint = authEntryPoint;
this.userDetailsService = userDetailsService;
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(e -> {
e.authenticationEntryPoint(authEntryPoint);
})
.authorizeHttpRequests(r -> {

r.requestMatchers(HttpMethod.POST, "/api/authentication/respondents").authenticated();
})
.httpBasic(Customizer.withDefaults());
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public Filter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
}
Мой поставщик токенов

Код: Выделить всё

@Component
public class TokenProvider {

private final SecuritySettings securitySettings;

@Autowired
public TokenProvider(SecuritySettings securitySettings) {
this.securitySettings = securitySettings;
}

public String generateToken(Authentication authentication){
String username = authentication.getName();
Date curretDate = new Date();
int expiration = securitySettings.getExpiration();
Date expireDate = new Date(curretDate.getTime() + expiration);

String token = Jwts.builder()
.setSubject(username)
.setIssuedAt(curretDate)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, securitySettings.getKey())
.compact();

return token;
}

public String getUsernameFromJwt(String token){
Claims claims = Jwts.parser()
.setSigningKey(securitySettings.getKey())
.parseClaimsJws(token)
.getBody();

return claims.getSubject();
}

public boolean validateToken(String token){
try{
Jwts.parser()
.setSigningKey(securitySettings.getKey())
.parseClaimsJws(token);
return true;
} catch (Exception e){
throw new AuthenticationCredentialsNotFoundException("Jwt was expired or incorrect");
}
}
}
Фильтр аутентификации:

Код: Выделить всё

public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired
private TokenProvider tokenProvider;
@Autowired
private UserDetailsServiceImpl userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String token = getJWTFromRequest(request);
if (StringUtils.hasText(token) &&  tokenProvider.validateToken(token)){
String username = tokenProvider.getUsernameFromJwt(token);

UserDetails user = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,
user.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
filterChain.doFilter(request, response);
}

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;
}
}
реализация службы сведений о пользователях:

Код: Выделить всё

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

private IdentityUserRepository identityUserRepository;

@Autowired
public UserDetailsServiceImpl(IdentityUserRepository identityUserRepository) {
this.identityUserRepository = identityUserRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
IdentityUser databaseUser = identityUserRepository
.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Username not found"));
return new User(databaseUser.getUsername(), databaseUser.getPasswordHash(), mapRolesToAuthorities(databaseUser));
}

private List mapRolesToAuthorities(IdentityUser user){
List authorities = new ArrayList();
authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getRole()));
return authorities;
}

}
Я потратил около 15 часов, пытаясь найти некоторую информацию и решить эту проблему, но ничего не помогло. Единственное, что я обнаружил, это то, что я всегда добираюсь до этой точки входа:

Код: Выделить всё

@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
И я думаю, отсюда возвращается 401. В сообщении об исключении говорится: «Для доступа к этому ресурсу требуется полная аутентификация»... Я был бы очень благодарен, если бы кто-нибудь мне помог. Возможно, я также упомяну, что моя цель — ограничить конечную точку пользователями с правами администратора с помощью hasRole("ADMIN") (это также оставляет меня с 401). И чтобы внести ясность: токен носителя JWT, переданный в заголовке аутентификации, действителен.

Подробнее здесь: https://stackoverflow.com/questions/787 ... ssed-a-val
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»