Доступ на основе ролей Spring Boot: невозможно получить доступ на основе конечной точкиJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Доступ на основе ролей Spring Boot: невозможно получить доступ на основе конечной точки

Сообщение Anonymous »

У меня есть пользователь с ролью «ROLE_USER», я могу без проблем войти в систему этого пользователя, и конечная точка входа без проблем генерирует JWT каждый раз, когда я нажимаю на нее. Я пытаюсь запустить конечную точку с пользователем, вошедшим в систему, с помощью jwt и аутентификации на основе ролей. Когда я пытаюсь запустить конечную точку ниже, я получаю эти две ошибки:

d.s.s.security.jwt.JwtUtils: Неверная подпись JWT: подпись JWT не соответствует локально вычисленная подпись. Валидность JWT не может быть подтверждена, и ей не следует доверять.


d.s.s.security.jwt.AuthEntryPointJwt: Несанкционированная ошибка: полная
Для доступа к этому ресурсу требуется аутентификация

Вот соответствующий код ниже:
AuthController.java:

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

package dev.spring.spring_jwt_auth.controller;

import dev.spring.spring_jwt_auth.model.EnumRole;
import dev.spring.spring_jwt_auth.model.Role;
import dev.spring.spring_jwt_auth.model.User;
import dev.spring.spring_jwt_auth.payload.request.LoginRequest;
import dev.spring.spring_jwt_auth.payload.request.SignupRequest;
import dev.spring.spring_jwt_auth.payload.response.JwtResponse;
import dev.spring.spring_jwt_auth.repository.RoleRepository;
import dev.spring.spring_jwt_auth.repository.UserRepository;
import dev.spring.spring_jwt_auth.security.jwt.JwtUtils;
import dev.spring.spring_jwt_auth.security.services.RefreshTokenService;
import dev.spring.spring_jwt_auth.security.services.UserDetailsImpl;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class AuthController {

private AuthenticationManager authenticationManager;
private UserRepository userRepository;
private RoleRepository roleRepository;
private JwtUtils jwtUtils;
private PasswordEncoder passwordEncoder;
private RefreshTokenService refreshTokenService;

@Autowired
public AuthController(AuthenticationManager authenticationManager,
UserRepository userRepository,
PasswordEncoder passwordEncoder,
RoleRepository roleRepository,
JwtUtils jwtUtils,
RefreshTokenService refreshTokenService) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.roleRepository = roleRepository;
this.jwtUtils = jwtUtils;
this.refreshTokenService = refreshTokenService;
}

public AuthController() {
}

@PostMapping("/signin")
public ResponseEntity signin(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String token = jwtUtils.generateToken(authentication);

UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List roles = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList();

return ResponseEntity.ok(new JwtResponse(token, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail(), roles));
}

@PostMapping("/signup")
public ResponseEntity signup(@Valid @RequestBody SignupRequest signupRequest) {
if (userRepository.existsByUsername(signupRequest.getUsername())) {
return ResponseEntity.badRequest().body("Username is already taken");
}
if (userRepository.existsByEmail(signupRequest.getEmail())) {
return ResponseEntity.badRequest().body("Email is already taken");
}

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode(signupRequest.getPassword());
User user = new User(signupRequest.getUsername(), signupRequest.getEmail(), encodedPassword);
Set userRoles = signupRequest.getRoles();
Set  roles = new HashSet();

if (userRoles == null) {
Role role = roleRepository.findByName("ROLE_USER").orElseThrow(() -> new RuntimeException("Role is not found"));
roles.add(role);
} else {
userRoles.forEach(role -> {
if (role.getName().equals("ROLE_ADMIN")) {
Role role1 = roleRepository.findByName("ROLE_ADMIN").orElseThrow(() -> new RuntimeException("Role is not found"));
roles.add(role1);
} else if (role.getName().equals("ROLE_MODERATOR")) {
Role role1 = roleRepository.findByName("ROLE_MODERATOR").orElseThrow(() -> new RuntimeException("Role is not found"));
roles.add(role1);
} else {
Role role1 = roleRepository.findByName("ROLE_USER").orElseThrow(() -> new RuntimeException("Role is not found"));
roles.add(role1);
}
});
}
user.setRoles(roles);
userRepository.saveAndFlush(user);
return ResponseEntity.ok(user);
}
}
TestController.java

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

package dev.spring.spring_jwt_auth.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/test")
public class TestController {

@GetMapping("/all")
public String all() {
return "public content";
}

@GetMapping("/user")
@PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_MODERATOR') or hasRole('ROLE_ADMIN')")
public String user() {
return "user content";
}

@GetMapping("/moderator")
@PreAuthorize("hasRole('ROLE_MODERATOR') or hasRole('ROLE_ADMIN')")
public String mod() {
return "moderator content";
}

@GetMapping("/admin")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String admin() {
return "admin content";
}
}
AuthEntryPointJwt.java:

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

package dev.spring.spring_jwt_auth.security.jwt;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;

@Component
public class AuthEntryPointJwt implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
logger.error("Unauthorized error: {}", authException.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

HashMap  body = new HashMap();
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
body.put("error", "Unauthorized");
body.put("message", authException.getMessage());
body.put("path", request.getServletPath());

final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), body);
}
}
WebSecurityConfig.java:

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

package dev.spring.spring_jwt_auth.security;

import dev.spring.spring_jwt_auth.security.jwt.AuthEntryPointJwt;
import dev.spring.spring_jwt_auth.security.jwt.AuthTokenFilter;
import dev.spring.spring_jwt_auth.security.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableMethodSecurity
public class WebSecurityConfig {

private UserDetailsServiceImpl userDetailsService;
private AuthEntryPointJwt entryPointJwt;

@Autowired
public WebSecurityConfig(UserDetailsServiceImpl userDetailsService, AuthEntryPointJwt entryPointJwt) {
this.userDetailsService = userDetailsService;
this.entryPointJwt = entryPointJwt;
}

@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}

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

@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider =new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}

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

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(e -> e.authenticationEntryPoint(entryPointJwt))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth ->  auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/test/**").authenticated());
http.authenticationProvider(daoAuthenticationProvider());
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
AuthTokenFilter.java

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

package dev.spring.spring_jwt_auth.security.jwt;

import dev.spring.spring_jwt_auth.security.services.UserDetailsServiceImpl;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

public class AuthTokenFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailsServiceImpl userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String jwt = parseJwt(request);
try {
if (jwt != null && jwtUtils.validateToken(jwt)) {
String username = jwtUtils.generateUsernameFromToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,
null,
userDetails.getAuthorities());

authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (Exception e) {
logger.error("Cannot set user authentication {}", e);
}
filterChain.doFilter(request, response);
}

private String parseJwt(HttpServletRequest request) {
String header = request.getHeader("Authorization");

if (StringUtils.hasText(header) &&  header.startsWith("Bearer ")) {
return header.substring(7);
}
return null;
}
}
JwtUtils.java:

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

package dev.spring.spring_jwt_auth.security.jwt;

import dev.spring.spring_jwt_auth.security.services.UserDetailsImpl;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;

@Component
public class JwtUtils {

private final Logger logger = LoggerFactory.getLogger(JwtUtils.class);

@Value("${app.secretKey}")
private String secretKey;

@Value("${app.jwtExpirationTime}")
private int jwtExpirationTime;

public String generateToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();

return Jwts.builder()
.subject((userPrincipal.getUsername()))
.issuedAt(new Date())
.expiration(new Date((new Date()).getTime() + jwtExpirationTime))
.signWith(Jwts.SIG.HS512.key().build(), Jwts.SIG.HS512)
.compact();
}

public SecretKey key() {
return Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretKey));
}

public String generateUsernameFromToken(String token) {
return Jwts
.parser()
.verifyWith(Jwts.SIG.HS512.key().build())
.build()
.parseSignedClaims(token)
.getPayload()
.getSubject();
}

public boolean validateToken(String token) {
try {
Jwts
.parser()
.verifyWith(Jwts.SIG.HS512.key().build())
.build()
.parseSignedClaims(token);
return true;
} catch (SignatureException e) {
logger.error("Invalid JWT signature: {}", e.getMessage());
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}
Любая помощь приветствуется!

Подробнее здесь: https://stackoverflow.com/questions/792 ... oint-based
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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