我将/admin
端点添加到antMatchers("/admin").hasAuthority("ADMIN")
时遇到了这个问题
它只是不会向/admin
发出 GET 请求并返回200
,而是返回403
注意:我正在使用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";
}
奇怪的是,使用邮递员,我被重定向了!
我在这里想念什么?
编辑:第一个电话是在/authenticate/web
,我告诉spring我已通过身份验证
authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(auth.getUsername(), auth.getPassword()));
编辑2:
使情况更清晰:
访问网络 的流程:
/authenticate/web
.js
重定向到/authority
(GET)/admin
(GET)-> 403 访问邮递员 ,流程:
/authenticate/web
JWT
并将其包含在标题中,然后对/authority
进行真的很奇怪,我每次在{strong> web 流中将jwt
与response.addHeader
添加在一起。
更新:
加上JWT
。
尽管现在我注意到我从网上获得了 302 ,而不是 200
您将看到admin
页面是 403
更新2:
我已经设法分解了几件事, 首先
通过对我的安全性使用httpSecurity.addFilterBefore
配置意味着spring将寻找JWT
并在指定过滤器类的位置之前添加过滤器
权限已正确分配给用户,因此没有问题 在那里
我将hasAuthority()
更改为hasRole()
如果您获得当前用户,则可以如下所示自动访问其权限
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("Principal: "+auth.getPrincipal());
System.out.println("Authorities: "+auth.getAuthorities());
因为
authentication
被jwt filter
覆盖, 意味着我只会在请求标头时设法获取用户 包含有效的jwt
这就是为什么它在postman
上有效但在web
上无效的原因。
另一个问题是在控制器中,我试图在jwt
标头上添加response
,仅在控制器完成其工作时才会添加到标头中,我无法进入用户委托人的下一行是因为请求标头中没有jwt
。
此屏幕快照表示一个网络呼叫和来自邮递员的呼叫,两个人都访问/authority
端点。
ADMIN
视为授权机构ROLE_ANONYMOUS
所以我有两种选择来解决这个问题:
REST
保护JWT
端点,并为Web部件使用默认的弹簧安全性(hasRole()
等)。答案 0 :(得分:2)
经过反复试验,我设法分解了几件事,并使用JWT
和默认的 authentication 弹簧使安全性正常工作。
要使其正常工作,我必须完全更改我的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)
JWT @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();
}
}
对于这些配置,我们基本上说的是:
JWT
上寻找/api/**
/web/**
上寻找权限因此,像/web
这样的所有/web/admin
端点都将需要authorities
而不是JWT
!
,来自/api/**
的所有敏感信息都需要JWT
答案 1 :(得分:1)
在浏览器中启用开发人员工具,并从Web捕获GET /authority
的请求和响应标头。即您的网络流程的第二步
捕获来自邮递员的GET /authority
的请求和响应标头。即。邮递员流程的第二步
比较它们(或在此处发布)
基于发布的屏幕截图进行更新
从网络访问:
POST /authenticate/web
-这就是成功GET /authority
-这也是成功的,因为它确实完成了将其重定向到/admin
的工作。/admin
,因此这里没有问题)/admin
的自动重定向请求以403失败(因为按预期,没有人向请求添加jwt标头,因为它不是cookie或不是重定向URL或某些会话的查询参数的一部分会话保持)(这是正确的预期行为)。看到这个问题。 How to forward headers on HTTP redirect 邮递员的来访:
POST /authenticate/web
这就是成功/admin
,就像在网络流程中一样
(邮递员保留了原始的jwt标头,并将其也转发到重定向的url,但它不应该这样做)摘要
总而言之,postman和web在重定向上的行为不同。即在重定向上,postman发送原始标头(在您的情况下为jwt),而浏览器不保留原始http标头。
因此,您必须重新设计应用程序。 例如,
/authority
端点的响应,并使用http标头将其手动转发到/admin
答案 2 :(得分:0)
如Spring Security所建议的那样,在不安全的映射之前进行安全保护的映射,在这种情况下,
.antMatchers(“ / admin”)。hasAuthority(“ ADMIN”)
必须先出现在不安全的映射(“ /”,“ / authority”及其他)之前,在“授权”部分中,这可能是导致问题的原因。
答案 3 :(得分:-1)
.antMatchers("/admin").hasAuthority("ADMIN")
它可以代替"/admin"
使用"/admin/**"