Springboot如何在Zuul微服务上验证令牌 [英] Springboot how to validate token on Zuul microservice

查看:403
本文介绍了Springboot如何在Zuul微服务上验证令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Springboot and im trying to filter requests through a Zuul API gateway however i get the error below :

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

AnonymousAuthenticationToken cannot be cast to org.aacctt.ms.auth.security.JWTAuthentication

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

When i put a breakpoint i get a null header/token string value when the request reaches the authentication service from zuul gateway, this happens for protected requests that require an authorization token.

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

My aim is to be able to verify the token sent by clients so that i can allow the client's request to protected endpoints or reject it.

我不确定这是我的代码在哪里做错了

Im not sure what im doing wrong here is my code:

身份验证服务


@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);
    }

}

WebSecurityConfig


@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();
    }

}

JWTAuthentication

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);
    }
}

SecurityService

@Service
public class SecurityService {

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

}


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<>());

     }
}

推荐答案

问题是敏感标头,Authorization默认是Zuul中的敏感标头,您只需要覆盖敏感标头即可.

The issue is the sensitive header, Authorization is sensitive header by default in Zuul, you just need to override the sensitive headers.

zuul:
  sensitive-headers:
  -

通过在Zuul网关应用程序中设置此属性.yml使用Authorization标头将请求路由到身份验证服务

By setting this property in Zuul gateway application.yml it route request to auth service with the Authorization header

仅参考:

身份验证服务参考

Auth Service reference

基于JWT的身份验证 https://github.com/nikhilmalavia/SpringBootJWT.git

JWT based authentication https://github.com/nikhilmalavia/SpringBootJWT.git

这篇关于Springboot如何在Zuul微服务上验证令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆