尝试访问不安全的路由时出错
Gettig error while trying to access unsecured route
我在我的 java 项目中使用 spring 安全性来保护 Web 服务。
我所有的 Web 服务都在这里受到保护,是我使用的过滤器链配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated();
}
现在我需要创建一个每个人都可以访问的 Web 服务。
为此,我添加了这一行:
.and().authorizeRequests().antMatchers("/auth/reset").permitAll()
链接文件管理器,它看起来像这样:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.and().authorizeRequests().antMatchers("/auth/reset").permitAll()
.anyRequest()
.authenticated();
}
添加上面的行后我得到异常 JWT not found,它来自这个 JwtTokenVerifier bean,它被触发
addFilterAfter.
我的问题是,在请求不安全的 Web 服务时,如何防止触发 addFilterAfter 或仅安全路由所需的任何其他过滤器?
更新
这里是 JwtTokenVerifier bean 的定义:
public class JwtTokenVerifier extends OncePerRequestFilter {
private final SecretKey secretKey;
private final JwtConfig jwtConfig;
public JwtTokenVerifier(SecretKey secretKey,
JwtConfig jwtConfig) {
this.secretKey = secretKey;
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
filterChain.doFilter(request, response);
return;
}
String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
Claims body = claimsJws.getBody();
String email = body.getSubject();
var authorities = (List<Map<String, String>>) body.get("authorities");
Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
.map(m -> new SimpleGrantedAuthority(m.get("authority")))
.collect(Collectors.toSet());
Authentication authentication = new UsernamePasswordAuthenticationToken(
email,
null,
simpleGrantedAuthorities
);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (JwtException e) {
throw new IllegalStateException(String.format("Token %s cannot be trusted", token));
}
filterChain.doFilter(request, response);
} catch (JwtException e) {
throw e;
}
}
}
你试过类似的东西吗:
.and()
.authorizeRequests()
.antMatchers("...").permitAll()
.and()
.addFilter(...)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
我知道你没有问这个,但我首先建议你使用 Spring 安全的 built-in JWT support 而不是构建你自己的。安全很难,使用经过审查的支持可能更安全。
关于您关于为单独的端点使用单独的身份验证机制的问题,您可以改为发布两个过滤器链,一个用于开放端点,一个用于 token-based 个端点,如下所示:
@Bean
@Order(0)
SecurityFilterChain open(HttpSecurity http) {
http
.requestMatchers((requests) -> requests.antMatchers("/auth/reset"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());
return http.build();
}
@Bean
SecurityFilterChain tokenBased(HttpSecurity http) {
http
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.addFilter(...)
.addFilterAfter(...);
return http.build();
}
我在我的 java 项目中使用 spring 安全性来保护 Web 服务。 我所有的 Web 服务都在这里受到保护,是我使用的过滤器链配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated();
}
现在我需要创建一个每个人都可以访问的 Web 服务。 为此,我添加了这一行:
.and().authorizeRequests().antMatchers("/auth/reset").permitAll()
链接文件管理器,它看起来像这样:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
.authorizeRequests()
.and().authorizeRequests().antMatchers("/auth/reset").permitAll()
.anyRequest()
.authenticated();
}
添加上面的行后我得到异常 JWT not found,它来自这个 JwtTokenVerifier bean,它被触发 addFilterAfter.
我的问题是,在请求不安全的 Web 服务时,如何防止触发 addFilterAfter 或仅安全路由所需的任何其他过滤器?
更新
这里是 JwtTokenVerifier bean 的定义:
public class JwtTokenVerifier extends OncePerRequestFilter {
private final SecretKey secretKey;
private final JwtConfig jwtConfig;
public JwtTokenVerifier(SecretKey secretKey,
JwtConfig jwtConfig) {
this.secretKey = secretKey;
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
filterChain.doFilter(request, response);
return;
}
String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
Claims body = claimsJws.getBody();
String email = body.getSubject();
var authorities = (List<Map<String, String>>) body.get("authorities");
Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
.map(m -> new SimpleGrantedAuthority(m.get("authority")))
.collect(Collectors.toSet());
Authentication authentication = new UsernamePasswordAuthenticationToken(
email,
null,
simpleGrantedAuthorities
);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (JwtException e) {
throw new IllegalStateException(String.format("Token %s cannot be trusted", token));
}
filterChain.doFilter(request, response);
} catch (JwtException e) {
throw e;
}
}
}
你试过类似的东西吗:
.and()
.authorizeRequests()
.antMatchers("...").permitAll()
.and()
.addFilter(...)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
我知道你没有问这个,但我首先建议你使用 Spring 安全的 built-in JWT support 而不是构建你自己的。安全很难,使用经过审查的支持可能更安全。
关于您关于为单独的端点使用单独的身份验证机制的问题,您可以改为发布两个过滤器链,一个用于开放端点,一个用于 token-based 个端点,如下所示:
@Bean
@Order(0)
SecurityFilterChain open(HttpSecurity http) {
http
.requestMatchers((requests) -> requests.antMatchers("/auth/reset"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());
return http.build();
}
@Bean
SecurityFilterChain tokenBased(HttpSecurity http) {
http
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.addFilter(...)
.addFilterAfter(...);
return http.build();
}