我正在使用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服务器安全性的微服务?
答案 0 :(得分:1)
首先(如果我已经正确理解)安全实现是在代理上?因为代理必须只有两件事要做:过滤和路由......
我的microservces应用程序流程,我已经实现了如下图所示:
流程应该是这样的: https://tools.ietf.org/html/rfc6749#page-7
关于流程的简短说明:
在AccountServices中,您必须实现一个配置类来解码access_token并检查用户是否有权访问所请求的资源
这里也是一篇很好的文档,你可以在这里找到关于在Spring中实现的OAuth2框架:http://projects.spring.io/spring-security-oauth/docs/oauth2.html
一些代码:
在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());
}
}
关于公钥和私钥 私钥只能由AuthServer知道,并且必须在包括AuthService在内的任何服务中传递公钥。您可以在此处生成公钥和私钥:http://travistidwell.com/jsencrypt/demo/并在 application.yml 文件中添加这些密钥,并使用@Value
传递到配置类。
在资源服务器上
@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();
}
}
你唯一要做的就是为资源服务(AccountService)创建一个配置类来解码access_token并检查用户是否有ROLE来做某事......在这里你必须只传递公钥以相同的方式 application.yml 文件。
关于@EnableGlobalMethodSecurity(prePostEnabled = true)
注释,您可以在控制器方法上添加@preauthorize
注释。