源码:Securing your Microservices
小笔记:验证与授权,验证是看他是谁,授权是可以让他干些什么,所以授权之前肯定是要先验证的。
先把配置服务搞一下。
新建User表。
启动顺序:Eureka->配置服务->验证服务(端口号设一下:8901)
需要注意的几点:
返回的结果是:
{
"access_token": "96040f35-8b10-491d-a82b-1c1a835ba632",
"token_type": "bearer",
"refresh_token": "f933f8b1-cace-4a1a-bc75-ff7b58b37d3d",
"expires_in": 43199,
"scope": "webclient"
}
{
"user": {
"password": null,
"username": "john.carnell",
"authorities": [
{
"authority": "ROLE_USER"
}
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true
},
"authorities": [
"ROLE_USER"
]
}
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.security.oauthgroupId>
<artifactId>spring-security-oauth2artifactId>
dependency>
然后将引导类设为受保护资源:
它会强制执行一个过滤器,该过滤器就是来检查调用的HTTP首部中是否存在OAuth2访问令牌,然后调用刚才填写的回调地址验证它是不是有效的。得知它是有效的之后,还会应用定义好的任何访问控制规则,以控制什么人可以访问什么服务。
访问规则可以按照标准设置的非常细,这里只讨论两个。
组织服务定为8085。先运行一下,如果访问的时候不带令牌的话,会直接收到401错误。
然后我们把令牌带上,发现就可以了。
把Zuul开起来再试试:
没毛病。
接下来会锁定组织服务的DELETE调用,只让有ADMIN访问权限的人使用。注意这条以及下面的hasRole(“ADMIN”):
最后两句还是定义了其他端点都需要被授权。
如果我们用普通用户登录的令牌去删除的话,就会收到403
而如果用admin的话,则收到204成功。
数据库里看一下,果然被删了。
像上一章一样,微服务是在调用微服务的,如果我访问了微服务A,带着令牌,微服务A自己又调用了微服务B,如果B也受资源保护的话,那么这个令牌也是要自动带上的。这一小节就是为了解决这个问题。
在开启了Zuul网关的情况下,实现这些要做两件事:
在配置服务里对Zuul做以下配置:
zuul.sensitiveHeaders: Cookie,Set-Cookie
这个配置是黑名单的意思,没在这个上面的,都会传播到下一层服务,Authorition不再这个上面,所以会传播。
我们就俩主要服务,而且传播都是许可证到组织的,这个很好理解。
基本的授权就不说了,直接说怎么传播令牌:
OAuth2作为验证框架,没有标准,比较搞笑,JWT是后来矫正OAuth2的标准,JWT具有以下特点:
pom依赖:
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-jwtartifactId>
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服务中。
刚才定义的内容,将在这里注入:
验证:运行Eureka->配置服务->验证服务
返回的token已经是Base64了,找个在线解密的网站解密一下:在线操作
到目前为止,已经有了验证服务。接下来就是配置许可证和组织服务以使用JWT。要做两件事:
(1)将Spring-security-jwt依赖项添加到pom文件。
(2)创建一个JWTTokenStoreConfig类。几乎和之前的相同。这个没必要再写一遍,只需要把传播搞定就行了。
注意刚才的解密,发现有些字段不是JWT令牌字段,这些就是扩展进来的。
通过向验证服务添加一个Spring OAuth2令牌增强器类,可以很轻松的扩展JWT令牌。
需要做的最后一件事就是告诉OAuth2服务使用这个类,首先为这个类公开一个Bean。
公开之后就受IOC管理了,就可以自动装配进相应的地方了:
这里从Zuul网关开始说起:
pom增加依赖:
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.7.0version>
dependency>
(1)对所有服务通信使用HTTPS。
(2)所有服务调用都应通过API网关。
(3)将服务划分到公共API和私有API。
这个值得讨论,很多人觉得公网下加密,内网下相互调用就不用加密,但是一旦网络被攻破,那就比较惨了,所以还是两个地方都加密的好,虽然开发的时候麻烦了点儿,但是没了后顾之忧。
(4)通过封锁不需要的网络端口来限制微服务的攻击面。