首页 > 解决方案 > 尽管我有管理员权限,但 Spring Boot 返回 403

问题描述

/admin当我向它添加端点时,我遇到了这个问题antMatchers("/admin").hasAuthority("ADMIN") ,根本不会发出GET请求/admin并返回200403而是返回

注意:我使用 JWT 作为额外的身份验证层。

这是我的安全配置

httpSecurity.csrf().disable()
 .authorizeRequests().antMatchers("/", "/health", "/authority", "/dashboard", "/users/login", "/logoutUser", "/manageEvents", "/manageAeds", "/manageReports",
  "/charts", "/error", "/profile", "/authenticate/**", "/login", "/403", "/userProfile", "/deleteAed", "/users/add").permitAll()
 .antMatchers("/admin").hasAuthority("ADMIN")
 .antMatchers("/css/**", "/img/**", "/js/**", "/images/**", "/error_css/**", "/scss/**", "/vendor/**").permitAll()
 .anyRequest().authenticated().and().
exceptionHandling().accessDeniedPage("/403").and()
 .sessionManagement()
 .sessionCreationPolicy(SessionCreationPolicy.STATELESS);


httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

通过将其移至permit.All()它会起作用,但这里并非如此。

这是我在里面处理重定向的地方@Controller

@GetMapping("/authority")
public String getAuth(HttpServletResponse response) {

 if (jwt == null) {
  return "redirect:/login";
 }
 if (jwtTokenUtil.isTokenExpired(jwt)) {
  return "redirect:/login?token=expired";
 }
 response.addHeader("Auth", "Bearer " + jwt);

 System.out.println(loggedinUser.getRoles());

 if (loggedinUser != null) {
  if (loggedinUser.getRoles().equalsIgnoreCase("TILEFONITIS")) {
   return "redirect:/dashboard"; //will redirect
  } else if (loggedinUser.getRoles().equalsIgnoreCase("ADMIN")) {
   System.out.println("Admin");
   return "redirect:/admin"; //won't redirect
  } else if (loggedinUser.getRoles().equalsIgnoreCase("GUEST")) {
   return "redirect:/403"; // will redirect
  } else {
   return "redirect:/dashboard"; // will redirect
  }
 } else {
  return "redirect:/login";
 }

}

这是我的/admin内心@Controller,从来没有被召唤过。

@GetMapping("/admin")
public String getAdmin(HttpServletResponse response) {
 if (jwt == null) {
  return "redirect:/login";
 }
 if (jwtTokenUtil.isTokenExpired(jwt)) {
  return "redirect:/login?token=expired";
 }
 response.addHeader("Auth", "Bearer " + jwt);

 System.out.println("jwt" + jwt);

 return "admin";

}

奇怪的是,使用Postman ,我被重定向了!

我在这里想念什么?


编辑:第一个电话是在/authenticate/web我告诉春天我已通过身份验证的地方

authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(auth.getUsername(), auth.getPassword()));

编辑2:

为了让事情更清楚:

网络访问,流程:

  1. 邮政/authenticate/web
  2. 重定向.js/authority(GET)
  3. 不会重定向到/admin(GET) -> 403

Postman来访,流程:

  1. 邮政/authenticate/web
  2. 获取JWT并将其包含在标题中并进行 GET 到/authority
  3. 我看到了管理模板。-> 200

这真的很奇怪,我jwt每次都response.addHeader网络流上添加。


更新:

在此处输入图像描述

加上JWT.

在此处输入图像描述

虽然现在我注意到我从网上得到302而不是200

如您所见,admin页面是403

在此处输入图像描述


更新 2:

我已经设法分解了一些东西,首先

如果您获得当前用户,您可以自动访问它的权限,如下所示

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("Principal: "+auth.getPrincipal());
System.out.println("Authorities: "+auth.getAuthorities());             

因为authentication被覆盖了jwt filter这意味着我只有在请求标头包含有效的情况下才能设法获取用户jwt

这就是为什么它postmanweb.


另一个问题是,在我的控制器中,我试图添加标题,只有当控制器完成它的工作时才会添加到标题中,我无法进入用户主体的下一行,因为jwt它没有请求标头。response jwt

此屏幕截图表示网络呼叫和来自邮递员的呼叫,两者都访问/authority端点。

在此处输入图像描述

所以我有两个选择来解决这个问题:

  1. 将其添加到请求标头中。
  2. 使用 Web 部件的默认 spring 安全性(等)保护REST端点。JWThasRole()

标签: javaspringredirectspring-securityjwt

解决方案


经过大量的试验和错误,我设法分解了一些东西,并使安全性与JWT默认的 spring身份验证一起工作。

为了让它工作,我必须完全改变我的SecurityConfig,并将其更改为MultipleSecurity.

这就是多重​​安全的工作原理:

带有@Order(1)注释的安全配置被标记为首先要查找的内容。

@Order(1)
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

 @Bean
 public AuthenticationManager authenticationManagerBean() throws Exception {
  return super.authenticationManagerBean();
 }

 @Override
 protected void configure(HttpSecurity httpSecurity) throws Exception {
  httpSecurity.csrf().disable()
   .antMatcher("/api/**").authorizeRequests()
   .antMatchers("/api/authenticate/android").permitAll()
   .anyRequest().authenticated().and()
   .exceptionHandling().accessDeniedPage("/403").and().sessionManagement()
   .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
   .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
 }

}
  • @Order(1)智威汤逊
  • @Order(2)默认弹簧安全
@Order(2)
@Configuration
public class SecurityConfiguration2 extends WebSecurityConfigurerAdapter {

 @Override
 protected void configure(HttpSecurity httpSecurity) throws Exception {
  httpSecurity.authorizeRequests()
   .antMatchers("/web/**").hasAuthority("ADMIN")
   .and().formLogin().defaultSuccessUrl("/redirect")
   .and().logout()
   .permitAll();
 }

}

我们基本上用这些配置说的是:

  1. 寻找一个JWT/api/**
  2. 寻找当局在/web/**

所以现在所有的/web端点/web/admin都需要authorities而不是JWT

并且所有敏感信息/api/**都需要JWT


推荐阅读