使用Springboot进行JWT身份验证

时间:2018-03-20 12:06:11

标签: spring spring-boot spring-security netflix-zuul

我正在使用SpringBoot开发具有微服务架构的Rest后端。为了保护端点,我使用了JWT令牌机制。我正在使用Zuul API网关。

如果请求具有所需权限(来自JWT的ROLE),它将转发到正确的微服务。 Zuul api网关的“WebSecurityConfigurerAdapter”如下。

@Autowired
private JwtAuthenticationConfig config;

@Bean
public JwtAuthenticationConfig jwtConfig() {
    return new JwtAuthenticationConfig();
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .csrf().disable()
            .logout().disable()
            .formLogin().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .anonymous()
            .and()
                .exceptionHandling().authenticationEntryPoint(
                        (req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
            .and()
                .addFilterAfter(new JwtTokenAuthenticationFilter(config),
                        UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
                .antMatchers(config.getUrl()).permitAll()
                .antMatchers("/api/user/**").permitAll()
                .antMatchers("/api/package/**").hasRole("USER")
                .antMatchers("/api/dashboard/**").hasRole("USER")
                .antMatchers("/api/records/**").hasRole("USER");
}

通过这种方式,我必须在此课程中编写每个请求授权部分。所以我希望通过“EnableGlobalMethodSecurity”使用方法级安全性。

问题是如何将此安全机制与其他微服务连接起来。因为当我将弹簧安全依赖性添加到其他微服务时,它们表现为不同的弹簧安全模块。我应该如何告诉其他使用zuul服务器安全性的微服务?

1 个答案:

答案 0 :(得分:1)

首先(如果我已经正确理解)安全实现是在代理上?因为代理必须只有两件事要做:过滤和路由......

我的microservces应用程序流程,我已经实现了如下图所示: enter image description here

流程应该是这样的: https://tools.ietf.org/html/rfc6749#page-7

关于流程的简短说明:

  1. 登录时,您应该传递用户凭据
  2. 如果请求具有上下文路径" / security" (例如)您应该将请求重定向到AuthServer(您决定安全实现)
    1. 如果用户传递可用凭据,则AuthServer必须返回access_token。
    2. 拥有访问令牌,用户可以向AccountServices(资源服务)发出请求;
  3. 在AccountServices中,您必须实现一个配置类来解码access_token并检查用户是否有权访问所请求的资源

    这里也是一篇很好的文档,你可以在这里找到关于在Spring中实现的OAuth2框架:http://projects.spring.io/spring-security-oauth/docs/oauth2.html

    一些代码:

    1. 在AuthService上

      @Configuration
      @EnableAuthorizationServer
      public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
      
      public final static String RESOURCE_ID = "server-resource";
      
      @Value("${jwt.publicKey}")
      private String publicKey;
      
      @Value("${jwt.privateKey}")
      private String privateKey;
      
      @Autowired
      private AuthenticationManager authenticationManager;
      
      @Bean
      public TokenStore tokenStore() {
          return new JwtTokenStore(accessTokenConverter());
      }
      
      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
          converter.setVerifierKey(publicKey);
          converter.setSigningKey(privateKey);
          return converter;
      }
      
      @Bean
      public TokenEnhancer customTokenEnhancer() {
          return new CustomTokenEnhancer();
      }
      
      @Override
      public void configure(ClientDetailsServiceConfigurer client) throws Exception {
          client.inMemory()
              .withClient("client")
              .secret("clientsecret")
              .scopes("read", "write")
              .resourceIds("user")
              .authorizedGrantTypes("password", "refresh_token", "authorization_code")
              .authorities("ROLE_TRUSTED_CLIENT")
              .accessTokenValiditySeconds(tokenExpire) // one day available
              .refreshTokenValiditySeconds(refreshExpire);
      }
      
      @Override
      public void configure(AuthorizationServerSecurityConfigurer server) throws Exception {
          server
              .tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')")
              .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')"); 
      }
      
      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
          endpoints
              .tokenStore(tokenStore())
              .authenticationManager(authenticationManager)
              .accessTokenConverter(accessTokenConverter());
      }
      }
      
    2. 关于公钥和私钥 私钥只能由AuthServer知道,并且必须在包括AuthService在内的任何服务中传递公钥。您可以在此处生成公钥和私钥:http://travistidwell.com/jsencrypt/demo/并在 application.yml 文件中添加这些密钥,并使用@Value传递到配置类。

      1. 在资源服务器上

        @Configuration
        @EnableResourceServer
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        public class OAuth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
        
        @Value("${jwt.publicKey}")
        private String publicKey;
        
        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
        
        @Bean
        protected JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            converter.setVerifierKey(publicKey);
            return converter;
        }
        
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources
                .tokenStore(tokenStore())
                .resourceId("user");
        }
        
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .csrf().disable()
                .authorizeRequests().antMatchers("/**").permitAll();
        }
        
        }
        
      2. 你唯一要做的就是为资源服务(AccountService)创建一个配置类来解码access_token并检查用户是否有ROLE来做某事......在这里你必须只传递公钥以相同的方式 application.yml 文件。

        关于@EnableGlobalMethodSecurity(prePostEnabled = true)注释,您可以在控制器方法上添加@preauthorize注释。