保护微服务(Spring Cloud Security和OAuth2.0)

源码:Securing your Microservices

一、使用Spring和OAuth2来保护单个端点

1.建立验证服务

构建依赖项:
保护微服务(Spring Cloud Security和OAuth2.0)
保护微服务(Spring Cloud Security和OAuth2.0)

2.使用OAuth2.0服务注册客户端应用程序

小笔记:验证与授权,验证是看他是谁,授权是可以让他干些什么,所以授权之前肯定是要先验证的。
保护微服务(Spring Cloud Security和OAuth2.0)

3.配置用户

保护微服务(Spring Cloud Security和OAuth2.0)
上面两个返回的bean,就是在这里注入的:
保护微服务(Spring Cloud Security和OAuth2.0)

4.验证用户

先把配置服务搞一下。
保护微服务(Spring Cloud Security和OAuth2.0)
新建User表。
保护微服务(Spring Cloud Security和OAuth2.0)
启动顺序:Eureka->配置服务->验证服务(端口号设一下:8901)
需要注意的几点:
保护微服务(Spring Cloud Security和OAuth2.0)
保护微服务(Spring Cloud Security和OAuth2.0)
返回的结果是:

{
    "access_token": "96040f35-8b10-491d-a82b-1c1a835ba632",
    "token_type": "bearer",
    "refresh_token": "f933f8b1-cace-4a1a-bc75-ff7b58b37d3d",
    "expires_in": 43199,
    "scope": "webclient"
}

然后拿着token去验证这个用户:
保护微服务(Spring Cloud Security和OAuth2.0)
返回的结果:

{
    "user": {
        "password": null,
        "username": "john.carnell",
        "authorities": [
            {
                "authority": "ROLE_USER"
            }
        ],
        "accountNonExpired": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "enabled": true
    },
    "authorities": [
        "ROLE_USER"
    ]
}

二、使用Oauth2保护组织服务

1.POM依赖

<dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-security</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.security.oauth</groupId>
          <artifactId>spring-security-oauth2</artifactId>
      </dependency>

2.配置服务以指向OAuth2验证服务

保护微服务(Spring Cloud Security和OAuth2.0)
然后将引导类设为受保护资源:
保护微服务(Spring Cloud Security和OAuth2.0)
它会强制执行一个过滤器,该过滤器就是来检查调用的HTTP首部中是否存在OAuth2访问令牌,然后调用刚才填写的回调地址验证它是不是有效的。得知它是有效的之后,还会应用定义好的任何访问控制规则,以控制什么人可以访问什么服务。

3.定义谁可以访问服务

访问规则可以按照标准设置的非常细,这里只讨论两个。

  • 只有通过验证的用户才能访问服务URL
  • 只有具有特定角色的用户才能访问服务URL
(1)通过验证用户保护服务

保护微服务(Spring Cloud Security和OAuth2.0)
组织服务定为8085。先运行一下,如果访问的时候不带令牌的话,会直接收到401错误。
保护微服务(Spring Cloud Security和OAuth2.0)
然后我们把令牌带上,发现就可以了。
保护微服务(Spring Cloud Security和OAuth2.0)
把Zuul开起来再试试:
保护微服务(Spring Cloud Security和OAuth2.0)
没毛病。

(2)通过特定角色保护服务

接下来会锁定组织服务的DELETE调用,只让有ADMIN访问权限的人使用。注意这条以及下面的hasRole(“ADMIN”):
保护微服务(Spring Cloud Security和OAuth2.0)
最后两句还是定义了其他端点都需要被授权。
如果我们用普通用户登录的令牌去删除的话,就会收到403
保护微服务(Spring Cloud Security和OAuth2.0)
而如果用admin的话,则收到204成功。
保护微服务(Spring Cloud Security和OAuth2.0)
数据库里看一下,果然被删了。
保护微服务(Spring Cloud Security和OAuth2.0)

4.传播OAuth2访问令牌

像上一章一样,微服务是在调用微服务的,如果我访问了微服务A,带着令牌,微服务A自己又调用了微服务B,如果B也受资源保护的话,那么这个令牌也是要自动带上的。这一小节就是为了解决这个问题。
在开启了Zuul网关的情况下,实现这些要做两件事:

(1)修改Zuul服务网关

在配置服务里对Zuul做以下配置:

zuul.sensitiveHeaders: Cookie,Set-Cookie

这个配置是黑名单的意思,没在这个上面的,都会传播到下一层服务,Authorition不再这个上面,所以会传播。

(2)许可证服务配置以及更改

我们就俩主要服务,而且传播都是许可证到组织的,这个很好理解。
基本的授权就不说了,直接说怎么传播令牌:
保护微服务(Spring Cloud Security和OAuth2.0)
保护微服务(Spring Cloud Security和OAuth2.0)

三、JSON Web Token 与OAuth2

OAuth2作为验证框架,没有标准,比较搞笑,JWT是后来矫正OAuth2的标准,JWT具有以下特点:

  • 小巧-- base64,直接http传递
  • 密码签名–JWT令牌由颁发它的验证服务器签名,可以保证其没有被篡改。
  • 自包含–由于JWT令牌是密码签名的,所以接受该服务的微服务可以保证令牌的内容是有效的(验证就是为了验证其是否有效嘛~),因此,不需要调用验证服务就可以来确认令牌的内容
  • 可扩展–当验证服务生成一个令牌时,它可以在加密之前放入额外的信息。
    Spring cloud为JWT提供了开箱即用的支持,就是验证服务和受验证服务的配置方式不同而已。
    我们拉取JWT版本的代码:JWT版,记得改配置文件:
    保护微服务(Spring Cloud Security和OAuth2.0)

1.修改验证服务以颁发JWT令牌

pom依赖:

<dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-jwt</artifactId>
      </dependency>

然后增加个配置类:

@Configuration
public class JWTTokenStoreConfig {
    @Autowired
    private ServiceConfig serviceConfig;
    @Bean
    public TokenStore tokenStore(){
        return  new JwtTokenStore(jwtAccessTokenConverter());
    }
    @Bean
    @Primary //告訴Spring這個是首選的,
    public DefaultTokenServices tokenServices(){
        DefaultTokenServices defaultTokenServices=new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
    @Bean //在JWT和OAuth2服務器之間充當翻譯
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter=new JwtAccessTokenConverter();
        converter.setSigningKey(serviceConfig.getJwtSigningKey());//定义用于签署令牌的签名密钥
        return converter;
    }
    @Bean
    public TokenEnhancer jwtTokenEnhancer(){
        return new JWTTokenEnhancer();
    }
}

小笔记:这里是使用的对称加密,密钥在配置服务里配置:

signing.key: "345345fsdfsf5345"

刚才定义了如何创建和签名JWT令牌。现在要将它挂钩到OAuth2服务中。
刚才定义的内容,将在这里注入:
保护微服务(Spring Cloud Security和OAuth2.0)
验证:运行Eureka->配置服务->验证服务
保护微服务(Spring Cloud Security和OAuth2.0)
返回的token已经是Base64了,找个在线解密的网站解密一下:在线操作
保护微服务(Spring Cloud Security和OAuth2.0)

2.在微服务中使用JWT

到目前为止,已经有了验证服务。接下来就是配置许可证和组织服务以使用JWT。要做两件事:
(1)将Spring-security-jwt依赖项添加到pom文件。
(2)创建一个JWTTokenStoreConfig类。几乎和之前的相同。这个没必要再写一遍,只需要把传播搞定就行了。
保护微服务(Spring Cloud Security和OAuth2.0)
保护微服务(Spring Cloud Security和OAuth2.0)

3.扩展JWT令牌

注意刚才的解密,发现有些字段不是JWT令牌字段,这些就是扩展进来的。
保护微服务(Spring Cloud Security和OAuth2.0)
通过向验证服务添加一个Spring OAuth2令牌增强器类,可以很轻松的扩展JWT令牌。
保护微服务(Spring Cloud Security和OAuth2.0)
需要做的最后一件事就是告诉OAuth2服务使用这个类,首先为这个类公开一个Bean。
保护微服务(Spring Cloud Security和OAuth2.0)
公开之后就受IOC管理了,就可以自动装配进相应的地方了:
保护微服务(Spring Cloud Security和OAuth2.0)

4.从JWT令牌中解析自定义字段

这里从Zuul网关开始说起:
pom增加依赖:

<dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
      </dependency>

然后就可以使用这个库解密了:
保护微服务(Spring Cloud Security和OAuth2.0)

四、关于微服务安全的总结

(1)对所有服务通信使用HTTPS。
(2)所有服务调用都应通过API网关。
(3)将服务划分到公共API和私有API。
这个值得讨论,很多人觉得公网下加密,内网下相互调用就不用加密,但是一旦网络被攻破,那就比较惨了,所以还是两个地方都加密的好,虽然开发的时候麻烦了点儿,但是没了后顾之忧。
(4)通过*不需要的网络端口来限制微服务的攻击面。

上一篇:Spring Security 之多AuthenticationProvider认证模式实现


下一篇:8. Spring Security 5.1之 OAuth 2.0 Login