为啥对于拥有包含“正确”权限的 JWT 令牌的用户禁止使用此 API?
Posted
技术标签:
【中文标题】为啥对于拥有包含“正确”权限的 JWT 令牌的用户禁止使用此 API?【英文标题】:Why this API is forbidden for an user having a JWT token containing the "correct" authority?为什么对于拥有包含“正确”权限的 JWT 令牌的用户禁止使用此 API? 【发布时间】:2022-01-23 23:29:12 【问题描述】:我不太喜欢 Spring Security 和 JWT 令牌,我对我正在从事的项目有以下疑问。
基本上我有一个包含我的 Spring Security 配置的 SecurityConfiguration 类,正如您所见,它旨在处理 JWT 令牌:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
@Qualifier("customUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
private JwtConfig jwtConfig;
@Autowired
private JwtTokenUtil jwtTokenUtil;
private static final String[] USER_MATCHER = "/api/user/email/**";
private static final String[] ADMIN_MATCHER = "/api/users/email/**";
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity http) throws Exception
/*
* NOTE:
* Using hasRole expects the authority names to start with 'ROLE_' prefix
* Instead, we use hasAuthority as we can use the names as it is
*/
http.csrf().disable()
.authorizeRequests()
//.antMatchers(USER_MATCHER).hasAnyAuthority("USER")
.antMatchers(USER_MATCHER).hasAnyAuthority("CLIENT")
.antMatchers(ADMIN_MATCHER).hasAnyAuthority("ADMIN")
.antMatchers("/api/users/test").authenticated()
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
.anyRequest().denyAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(
new TokenVerificationFilter(authenticationManager(), jwtConfig, jwtTokenUtil),UsernamePasswordAuthenticationFilter.class);
/* To allow Pre-flight [OPTIONS] request from browser */
@Override
public void configure(WebSecurity web)
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
@Bean
public BCryptPasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
;
正如您在前面的代码中看到的,我有以下两个匹配器列表:
private static final String[] USER_MATCHER = "/api/user/email/**";
private static final String[] ADMIN_MATCHER = "/api/users/email/**";
目前两者都包含相同的 API 路径:/api/users/email/**。这是因为我最初的想法是这个 API 应该可供简单用户和管理员用户使用。
然后在代码中,您可以根据生成的令牌中包含的权限找到以下匹配器定义:
.antMatchers(USER_MATCHER).hasAnyAuthority("CLIENT")
.antMatchers(ADMIN_MATCHER).hasAnyAuthority("ADMIN")
(USER_MATCHER 与 CLIENT 权限相关,这是目前可以执行的最简单的操作类型...请不要付费太在意权威的名字了……这些主要是一些例子,然后我会更好地定义我的权威列表)。
这样做,我希望这个 /api/users/email/ API 必须为具有 ADMIN 权限的用户和用户启用拥有CLIENT权限。
但是好像不是真的,做个例子。我为具有 ADMIN 权限的用户生成令牌,如下所示:
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ4eHhAZ21haWwuY29tIiwibmFtZSI6IlJlbmF0byBudWxsIEdpYWxsaSIsInVzZXJfcHJvZmlsZXMiOlsiQURNSU4iXSwiZXhwIjoxNjQwMjg2NTY5LCJpYXQiOjE2NDAyMDAxNjksImF1dGhvcml0aWVzIjpbIkFETUlOIl19.WQGYKbo_ihrV2Nu1RlxrCweBpgU-Y-dNh9L6R9vrj3vhTyvbPlsyzWNPe8ljtP6WZ8_Vvv8FUDJIa6y5BLS1SA
使用https://jwt.io/网站可以看到这个token拥有ADMIN权限:
"sub": "xxx@gmail.com",
"name": "Renato null Gialli",
"user_profiles": [
"ADMIN"
],
"exp": 1640286569,
"iat": 1640200169,
"authorities": [
"ADMIN"
]
所以我使用这个令牌来调用我的目标 API (/api/users/email/),我得到了我期望的结果:
好的,现在我为我系统的另一个只有 CLIENT 权限的用户生成一个全新的 JWT 令牌。它会生成如下内容:
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ5eXlAZ21haWwuY29tIiwibmFtZSI6Ik1hcmlvIG51bGwgUm9zc2kiLCJ1c2VyX3Byb2ZpbGVzIjpbIkNMSUVOVCJdLCJleHAiOjE2NDAyODY5MzEsImlhdCI6MTY0MDIwMDUzMSwiYXV0aG9yaXRpZXMiOlsiQ0xJRU5UIl19.MYM6J3bGSK2PJvxPpi01BHjbcyOiONegYlbZ--lfEtg3p6Hw91acyKYC7KADC2KcJgcXnICJGmLTkPcrVIpfEw
像往常一样,使用https://jwt.io/,我可以检查它是否包含此权限,事实上它是:
"sub": "yyy@gmail.com",
"name": "Mario null Rossi",
"user_profiles": [
"CLIENT"
],
"exp": 1640286931,
"iat": 1640200531,
"authorities": [
"CLIENT"
]
所以现在我使用这个 newtoken 来调用我的目标 API (/api/users/email/),但是这个用户无法访问 API:
如您所见,使用此令牌似乎禁止 API 访问。
为什么如果在我的配置中我指定了定义在 USER_MATCHER 列表中的 API(所以之前的目标 API)应该也可以被拥有包含 CLIENT 的令牌的用户访问强>权威?
怎么了?或者我在权限定义逻辑中遗漏了什么?
【问题讨论】:
我建议您丢弃自定义令牌过滤器并使用自 2018 年以来 Spring Security 具有的内置 jwt 功能而不是 docs.spring.io/spring-security/reference/servlet/oauth2/…,因为编写自定义安全性是不好的做法,为什么要导入安全性框架如果你不打算使用它 【参考方案1】:听起来您希望 CLIENT 和 ADMIN 都可以访问 /api/users/email/
端点
而不是.antMatchers(ADMIN_MATCHER).hasAnyAuthority("ADMIN")
试试.antMatchers(ADMIN_MATCHER).hasAnyAuthority("ADMIN", "CLIENT)
【讨论】:
以上是关于为啥对于拥有包含“正确”权限的 JWT 令牌的用户禁止使用此 API?的主要内容,如果未能解决你的问题,请参考以下文章