Java Springboot如何在Zuul microservice上验证令牌

Java Springboot如何在Zuul microservice上验证令牌,java,spring-boot,jwt,netflix-zuul,Java,Spring Boot,Jwt,Netflix Zuul,我是Springboot新手,我试图通过Zuul API网关过滤请求,但我遇到以下错误: 无法将AnonymousAuthenticationToken强制转换为org.aacctt.ms.auth.security.JWTAuthentication 当我放置一个断点时,当请求从zuul网关到达身份验证服务时,我会得到一个空的头/令牌字符串值,对于需要授权令牌的受保护请求会发生这种情况 我的目标是能够验证客户端发送的令牌,以便允许客户端请求受保护的端点或拒绝它 我不确定我做错了什么这是我的代码

我是Springboot新手,我试图通过Zuul API网关过滤请求,但我遇到以下错误:

无法将AnonymousAuthenticationToken强制转换为org.aacctt.ms.auth.security.JWTAuthentication

当我放置一个断点时,当请求从zuul网关到达身份验证服务时,我会得到一个空的头/令牌字符串值,对于需要授权令牌的受保护请求会发生这种情况

我的目标是能够验证客户端发送的令牌,以便允许客户端请求受保护的端点或拒绝它

我不确定我做错了什么这是我的代码:

身份验证服务


@Component
public class JWTAuthorizationFilter extends GenericFilterBean {

    private static final Logger LOG = LoggerFactory.getLogger(JWTAuthorizationFilter.class);

    private static final String HEADER_STRING = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";

    @Value("${jwt.encryption.secret}")
    private String SECRET;

    @Value("${jwt.access.token.expiration.seconds}")
    private long EXPIRATION_TIME_IN_SECONDS;


    public String generateAccessToken(long userId) {
        return JWT.create()
                .withSubject(String.valueOf(userId))
                .withIssuedAt(new Date())
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME_IN_SECONDS * 1000))
                .sign(Algorithm.HMAC256(SECRET.getBytes()));
    }



    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String header = httpRequest.getHeader(HEADER_STRING);  // this is null

        if (header == null || !header.startsWith(TOKEN_PREFIX)) {
            chain.doFilter(httpRequest, httpResponse);
            return;
        }

        SecurityContextHolder.getContext().setAuthentication(getAuthentication(header));
        chain.doFilter(httpRequest, httpResponse);
    }

    private Authentication getAuthentication(String token) {

        final String username;
        try {
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRET.getBytes()))
                    .build()
                    .verify(token.replace(TOKEN_PREFIX, ""));
            username = jwt.getSubject();
        } catch (JWTVerificationException e) {
            LOG.debug("Invalid JWT", e);
            return null;
        }

        final Long userId;
        try {
            userId = Long.valueOf(username);
        } catch (NumberFormatException e) {
            LOG.debug("Invalid JWT. Username is not an user ID");
            return null;
        }

        LOG.debug("Valid JWT. User ID: " + userId);

        return new JWTAuthentication(userId);
    }

}

@Service
public class SecurityService {

    public long getLoggedUserId() {
        JWTAuthentication authentication = (JWTAuthentication) SecurityContextHolder.getContext().getAuthentication();
        return authentication.getUserId();
    }

}


网站安全配置


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final JWTAuthorizationFilter jwtAuthorizationFilter;

    public WebSecurityConfig(JWTAuthorizationFilter jwtAuthorizationFilter) {
        this.jwtAuthorizationFilter = jwtAuthorizationFilter;
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().disable();
        http.csrf().disable();
        http.addFilterAfter(jwtAuthorizationFilter, BasicAuthenticationFilter.class);
        http.authorizeRequests()
                .antMatchers("/**").permitAll()
                .antMatchers(AccountController.PATH_POST_SIGN_UP).permitAll()
                .antMatchers(AccountController.PATH_POST_REFRESH).permitAll()
                .antMatchers(AccountController.PATH_POST_LOGIN).permitAll()
                .antMatchers("/v2/api-docs",
                        "/swagger-resources/configuration/ui",
                        "/swagger-resources",
                        "/swagger-resources/configuration/security",
                        "/swagger-ui.html",
                        "/webjars/**").permitAll()
                .anyRequest().authenticated()
        ;
         http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
jwt认证

public class JWTAuthentication implements Authentication {

    private final long userId;

    public JWTAuthentication(long userId) {
        this.userId = userId;
    }

    @Override public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.emptySet();
    }

    @Override public Object getCredentials() {
        return null;
    }

    @Override public Object getDetails() {
        return null;
    }

    public long getUserId() {
        return userId;
    }

    @Override public Long getPrincipal() {
        return userId;
    }

    @Override public boolean isAuthenticated() {
        return true;
    }

    @Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        throw new UnsupportedOperationException("JWT authentication is always authenticated");
    }

    @Override public String getName() {
        return String.valueOf(userId);
    }
}
Zuul网关


public class AuthorizationFilter extends BasicAuthenticationFilter {

    private static final Logger LOG = LoggerFactory.getLogger(AuthorizationFilter.class);
    private static final String HEADER_STRING = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";

    Environment environment;

    public AuthorizationFilter(AuthenticationManager authManager, Environment environment) {
        super(authManager);
        this.environment = environment;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest req,
            HttpServletResponse res,
            FilterChain chain) throws IOException, ServletException {

        String authorizationHeader = req.getHeader(environment.getProperty("authorization.token.header.name"));

        if (authorizationHeader == null || !authorizationHeader.startsWith(environment.getProperty("authorization.token.header.prefix"))) {
            chain.doFilter(req, res);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }  

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req) {

        String token = req.getHeader(HEADER_STRING);

        final String username;
        try {
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(environment.getProperty("token.secret").getBytes()))
                    .build()
                    .verify(token.replace(TOKEN_PREFIX, ""));
            username = jwt.getSubject();
        } catch (JWTVerificationException e) {
            LOG.debug("Invalid JWT", e);
            return null;
        }

        final Long userId;
        try {
            userId = Long.valueOf(username);
        } catch (NumberFormatException e) {
            LOG.debug("Invalid JWT. Username is not an user ID");
            return null;
        }

        LOG.debug("Valid JWT. User ID: " + userId);

         return new UsernamePasswordAuthenticationToken(userId, null, new ArrayList<>());

     }
}


公共类授权筛选器扩展了基本身份验证筛选器{
私有静态最终记录器LOG=LoggerFactory.getLogger(AuthorizationFilter.class);
私有静态最终字符串头\u String=“授权”;
公共静态最终字符串令牌\u PREFIX=“Bearer”;
环境;
公共授权筛选器(AuthenticationManager authManager,环境){
超级经理;
这个。环境=环境;
}
@凌驾
受保护的无效doFilterInternal(HttpServletRequest请求,
HttpServletRes,
FilterChain链)抛出IOException、ServletException{
String authorizationHeader=req.getHeader(environment.getProperty(“authorization.token.header.name”);
if(authorizationHeader==null | |!authorizationHeader.startsWith(environment.getProperty(“authorization.token.header.prefix”)){
链式过滤器(要求、恢复);
返回;
}
UsernamePasswordAuthenticationTokenAuthentication=getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(身份验证);
链式过滤器(要求、恢复);
}  
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest请求){
字符串标记=req.getHeader(HEADER\u字符串);
最终字符串用户名;
试一试{
DecodedJWT jwt=jwt.require(Algorithm.HMAC256(environment.getProperty(“token.secret”).getBytes())
.build()
.验证(标记.替换(标记前缀“”);
username=jwt.getSubject();
}捕获(JWTVerificationException e){
LOG.debug(“无效JWT”,e);
返回null;
}
最终长用户ID;
试一试{
userId=Long.valueOf(用户名);
}捕获(数字格式){
LOG.debug(“无效的JWT.Username不是用户ID”);
返回null;
}
LOG.debug(“有效的JWT.User ID:+userId”);
返回新的UsernamePasswordAuthenticationToken(userId,null,new ArrayList());
}
}

问题是敏感头,
授权
在Zuul中默认为敏感头,您只需覆盖敏感头

zuul:
  sensitive-headers:
  -
通过在Zuul gateway application.yml中设置此属性,it将请求路由到具有
授权
头的身份验证服务

仅供参考:

身份验证服务引用

基于JWT的身份验证

标题仍然为空,我收到错误
org.springframework.security.authentication.AnonymousAuthenticationToken无法强制转换为org.aacctt.ms.auth.security.JWTAuthentication
您可以共享安全配置设置代码吗?