我在我的项目中使用 Spring GraphQL 和 Spring Security。我正在使用 JWT 对用户进行身份验证,因此我有一个安全过滤器来检查令牌的有效性。当token无效时,会抛出异常。 我试图将异常消息作为有效的 graphQL 响应返回,但我得到的只是:
{
"errors": {
"message": "Failed to execute 'text' on 'Response': body stream already read",
"stack": "TypeError: Failed to execute 'text' on 'Response': body stream already read\n at http://localhost:8080/graphiql?path=/graphql:78:33"
}
}
我在控制台中收到的错误是这样的:
com.auth0.jwt.exceptions.JWTDecodeException: The input is not a valid base 64 encoded string.
所以,我希望在“错误”“消息”中。
这是安全配置:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final AppUserDetailsService appUserDetailsService;
private final JwtFilter jwtFilter;
public SecurityConfig(AppUserDetailsService appUserDetailsService, JwtFilter jwtFilter) {
this.appUserDetailsService = appUserDetailsService;
this.jwtFilter = jwtFilter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth").permitAll()
.antMatchers("/graphiql").permitAll()
.antMatchers("/graphql").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
这是 jwtFilter:
@Log4j2
@Component
public class JwtFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final AppUserDetailsService userDetailsService;
public JwtFilter(JwtUtil jwtUtil, AppUserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull FilterChain filterChain) throws ServletException, IOException {
final String header = request.getHeader("Authorization");
String username = null;
String jwt = null;
try {
if (header != null && header.startsWith("Bearer ")) {
jwt = header.substring(7);
username = jwtUtil.getUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
} catch (Exception ex) {
log.error(ex.getMessage());
throw ex;
}
filterChain.doFilter(request, response);
}
}
有谁知道我怎样才能实现这一目标?
谢谢!
您可以使用
@GraphQlExceptionHandler
带注释的方法编写新的全局异常处理程序,并使用 GraphQLError
从那里自定义构建错误消息。有时,此类方法可能无法捕获过滤器抛出的错误,因为 graphql-java 引擎可能尚未在过滤器级别调用。要捕获此类错误,请在项目中定义一个 ErrorWebExceptionHandler
的 bean。