Я разрабатываю rest API для форума в весенней загрузке. У меня есть сопоставление GET для /api/v1/forum/threads, которое вернет все потоки. Но он возвращает 401 Unauthorized, когда я пытаюсь получить к нему доступ, даже если я авторизован.
Контроллер потоков:
@RestController
@RequestMapping("/api/v1/forum/threads")
public class ThreadController {
@Autowired
private ThreadService threadService;
@GetMapping
public ResponseEntity getAllCategories(){
List threads = threadService.findAll();
return ResponseEntity.ok(threads);
}
}
Потоковый сервис:
@Service
public class ThreadService {
@Autowired
private ThreadRepository threadRepository;
public Optional findById(long id) {
return threadRepository.findById(id);
}
public Optional findByName(String keyword){
return threadRepository.findByNameContainingIgnoreCase(keyword);
}
public Optional findByCategory(Long id){
return threadRepository.findByCategoryId(id);
}
public List findAll(){
return threadRepository.findAll();
}
public Optional findByContent(String keyword){
return threadRepository.findByContentContainingIgnoreCase(keyword);
}
public void createThread(Thread thread){
threadRepository.save(thread);
}
public void deleteThread(Long id){
threadRepository.deleteById(id);
}
}
Репозиторий тем:
@Repository
public interface ThreadRepository extends JpaRepository {
Optional findById(Long id);
Optional findByNameContainingIgnoreCase(String title);
Optional findByCategoryId(Long categoryId);
Optional findByContentContainingIgnoreCase(String keyword);
}
Конфигурация безопасности:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
UserDetailsService userDetailsService;
@Autowired
private JwtFilter jwtFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
return http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(request -> request
.requestMatchers("/api/v1/forum/threads/**").permitAll()
.anyRequest().permitAll()
)
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.httpBasic(Customizer.withDefaults())
.build();
}
@Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception{
AuthenticationManagerBuilder auth = http.getSharedObject(AuthenticationManagerBuilder.class);
auth.authenticationProvider(authenticationProvider());
return auth.build();
}
}
Фильтр JWT:
@Component
public class JwtFilter extends OncePerRequestFilter {
@Autowired
JwtUtil jwtUtil;
@Autowired
UserDetailsService userDetailsService;
private static final List PUBLIC_URLS = List.of(
"/api/v1/forum/categories/**",
"/api/v1/forum/threads/**"
);
private final AntPathMatcher pathMatcher = new AntPathMatcher();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
String path = request.getRequestURI();
// Проверяем, является ли URL публичным
boolean isPublic = PUBLIC_URLS.stream()
.anyMatch(publicUrl -> pathMatcher.match(publicUrl, path));
if (isPublic) {
filterChain.doFilter(request, response);
return;
}
if (jwt != null) {
if (jwtUtil.validateToken(jwt)) {
System.out.println(1);
String username = jwtUtil.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
System.out.println(2);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
filterChain.doFilter(request, response);
}catch (MalformedJwtException ex) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token");
} catch (ExpiredJwtException ex) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Expired JWT token");
} catch (UnsupportedJwtException ex) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unsupported JWT token");
} catch (IllegalArgumentException ex) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT claims string is empty");
} catch (Exception ex) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication error");
}
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
Я думал, что проблема может быть в фильтре JWT, который плохо написан, но, похоже, это не так. У меня есть аналогичное сопоставление Get в /api/v1/forum/categories, которое возвращает все категории без 401.
Я пробовал изменить конфигурацию безопасности и контроллер потоков. Вот мой контроллер категорий:
@RestController
@RequestMapping("/api/v1/forum/categories")
public class CategoryController {
@Autowired
private ThreadCategoryService threadCategoryService;
@GetMapping
public ResponseEntity getAllCategories(){
List categories = threadCategoryService.findAll();
return ResponseEntity.ok(categories);
}
@GetMapping("/{id}")
public ResponseEntity getCategoryById(@PathVariable long id) {
Optional category = threadCategoryService.findById(id);
if(category.isPresent()){
return ResponseEntity.ok(category.get());
}
return null;
}
@GetMapping("/title/{title}")
public ResponseEntity getCategoriesByTitle(@PathVariable String title) {
Optional categories = threadCategoryService.findByName(title);
if(categories.isPresent()){
return ResponseEntity.ok(categories);
}
return null;
}
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity createCategory(@RequestBody ThreadCategory category) {
ThreadCategory created = threadCategoryService.createCategory(category);
return ResponseEntity.ok(created);
}
@PutMapping("/{id}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity updateCategory(@PathVariable long id, @RequestBody ThreadCategory category) {
return threadCategoryService.findById(id)
.map(categoryToUpdate -> {
categoryToUpdate.setName(category.getName());
categoryToUpdate.setDescription(category.getDescription());
threadCategoryService.createCategory(category);
return ResponseEntity.ok(category);
})
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity deleteCategory(@PathVariable Long id) {
threadCategoryService.deleteCategoryById(id);
return ResponseEntity.ok("Категория удалена");
}
}
Подробнее здесь: https://stackoverflow.com/questions/790 ... authorized
Получение 401 на общедоступной странице, даже если я авторизован ⇐ JAVA
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение