《Spring Microservices in Action》
《Spring Cloud Alibaba 微服务原理与实战》
《B站 尚硅谷 SpringCloud 框架开发教程 周阳》
JWT 为 OAuth2 令牌提供规范标准,并且可以自定义 JWT 令牌;
<!-- JWT OAuth2 库 --><dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-jwt</artifactid> </dependency><!--security 通用安全库--><dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-security</artifactid> </dependency> <!--oauth2.0--><dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId></dependency>在 security 包或 config 包下;
@Configrationpublic class JWTTokenStoreConfig{ @Autowired private ServiceConfig serviceConfig; @Bean public TokenStore tokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } //用于从出示给服务的令牌中读取数据 @Bean @Primary //用于告诉 Spring,如果有多个特定类型的 bean(本例中为 DefaultTokenService),那么使用 @Primary 标注的 Bean 类型自动注入 public DefaultTikenServices tokenServices(){ DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setTokenStore(tokenStore()); defaultTokenServices.setSupportRefreshToken(true); return defaultTokenServices; } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ //在 JWT 和 OAuth2 服务器之间充当翻译 JwtAccessTokenConverter conver = new JwtAccessTokenConverter(); //定义将用于签署令牌的签名密钥 conver.setSigningKey(serviceConfig.getJwtSigningKey()); } @Bean public TokenEnhancer jwtTokenEnhancer(){ return new JWTTokenEnhancer(); }}@Configurationpublic class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private DefaultTokenServices tokenServices; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired private TokenEnhancer jwtTokenEnhancer; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter)); endpoints.tokenStore(tokenStore) //JWT,5.2中定义的命令存储将在这里注入 .accessTokenConverter(jwtAccessTokenConverter) //JWT,钩子,用于告诉 Spring Security OAuth2 代码使用 JWT .tokenEnhancer(tokenEnhancerChain) //JWT .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("eagleeye") .secret("thisissecret") .authorizedGrantTypes("refresh_token", "password", "client_credentials") .scopes("webclient", "mobileclient"); }}<!-- JWT OAuth2 库 --><dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-jwt</artifactid> </dependency><!--security 通用安全库--><dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-security</artifactid> </dependency> <!--oauth2.0--><dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId></dependency>@Configurationpublic class JWTTokenStoreConfig { @Autowired private ServiceConfig serviceConfig; //JWT @Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } //JWT @Bean @Primary public DefaultTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setTokenStore(tokenStore()); defaultTokenServices.setSupportRefreshToken(true); return defaultTokenServices; } //JWT @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(serviceConfig.getJwtSigningKey()); return converter; }}可以在主程序类里,也可以在主程序类所在包及其子包里;
@Primary@Beanpublic RestTemplate getCustomRestTemplate() { RestTemplate template = new RestTemplate(); List interceptors = template.getInterceptors(); if (interceptors == null) { //UserContextInterceptor 会将 Authorization 首部注入每个 REST 调用 template.setInterceptors(Collections.singletonList(new UserContextInterceptor())); } else { interceptors.add(new UserContextInterceptor()); template.setInterceptors(interceptors); } return template;}public class UserContextInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept( HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { HttpHeaders headers = request.getHeaders(); headers.add(UserContext.CORRELATION_ID, UserContextHolder.getContext().getCorrelationId()); //将授权令牌添加到 HTTP 首部 headers.add(UserContext.AUTH_TOKEN, UserContextHolder.getContext().getAuthToken()); return execution.execute(request, body); }}//需要扩展 TokenEnhancer 类public class JWTTokenEnhancer implements TokenEnhancer { @Autowired private OrgUserRepository orgUserRepo; //基于用户名查找用户的组织 ID private String getOrgId(String userName){ UserOrganization orgUser = orgUserRepo.findByUserName( userName ); return orgUser.getOrganizationId(); } //进行这种增强,需要覆盖 enhance() 方法 @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { Map<String, Object> additionalInfo = new HashMap<>(); String orgId = getOrgId(authentication.getName()); additionalInfo.put("organizationId", orgId); //所有附加属性放在 HashMap 中,并设置在传入该方法的 accessToken 变量上 ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return accessToken; }}@Beanpublic TokenEnhancer jwtTokenEnhancer() { return new JWTTokenEnhancer();}@Configurationpublic class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private DefaultTokenServices tokenServices; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; //自动装配 TokenEnhancer 类 @Autowired private TokenEnhancer jwtTokenEnhancer; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { //允许开发人员挂钩多个令牌增强器 TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter)); endpoints.tokenStore(tokenStore) //JWT .accessTokenConverter(jwtAccessTokenConverter) //JWT .tokenEnhancer(tokenEnhancerChain) //JWT,将令牌增强器链挂钩到传入 configure() 方法的 endpoints 参数 .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("eagleeye") .secret("thisissecret") .authorizedGrantTypes("refresh_token", "password", "client_credentials") .scopes("webclient", "mobileclient"); }}以下配置均在在 Zuul 网关服务里进行;
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version></dependency>private String getOrganizationId(){ String result=""; if (filterUtils.getAuthToken()!=null){ //从 HTTP 首部 Authorization 解析出令牌 String authToken = filterUtils.getAuthToken().replace("Bearer ",""); try { //传入用于签署令牌的签名密钥,使用 JWTS 类解析令牌 Claims claims = Jwts.parser() .setSigningKey(serviceConfig.getJwtSigningKey().getBytes("UTF-8")) .parseClaimsJws(authToken).getBody(); //从令牌中提取 xxxId result = (String) claims.get("organizationId"); } catch (Exception e){ e.printStackTrace(); } } return result;}