Spring Cloud 微服务实践 (5) - 认证中心
本文基于上一篇文章的理论,进行实际开发,在现有的Spring Cloud 微服务系统上集成Spring Cloud OAuth2,并且采用增强的JWT令牌传输用户授权。
1、源代码
Github上的地址: https://github.com/xiaoboey/from-zero-to-n/tree/master/two ,Spring Boot的版本是2.3.3,Spring Cloud的版本是Hoxton.SR8。
如果有一定的Spring Boot和Spring Cloud基础,是可以直接Clone代码,然后运行起来再结合代码来理解的。
2、OAuth2的非对称加密
这里我们用非对称加密来增强JWT的安全性:认证中心(AuthorizationServer)使用私钥签发JWT令牌,其他资源服务(ResourceServer)使用公钥来验证JWT令牌。非对称加密的这套机制可以确保只有认证中心才能签发令牌(授权),并且防止JWT在网络传输过程中被篡改,资源服务也可以确信JWT是认证中心签发的,这是非对称加密的“防篡改,不可抵赖”特性。
使用Java的keytool工具生成私钥:
keyalg: 加密算法
validity: 证书有效期,单位是天
注:截图里我是用的PowerShell,并且在命令行里指定了密码
查看证书:
导出公钥:
但是Spring Cloud OAuth2不认这个公钥,还需要用openssl来转换一下(可以在Git Bash中执行openssl):
注:上图中除了$ openssl那一行,其他就是导出的公钥,复制下来保存为oauth2-jwt.cert
3、认证中心(OAuth2 Server)
项目名称auth-server,pom.xml如下:
从pom.xml可以看出,auth-server项目多了数据库相关的依赖(jpa、h2)和权限控制方面的依赖(security、oauth2)。
之所以要引入JPA和H2,是因为auth-server作为认证中心,需要持有用户的账号密码和用户关联的角色信息,以便进行用户的认证和授权。数据库选H2是想方便大家验证代码,clone下来就可以直接编译跑起来。
配置文件application.yml:
注:ddl-auto设置为update,会自动根据Entity创建表。
JPA相关的配置JpaConfig.java
用户实体(User.java):
角色实体(Role.java):
注:GrantedAuthority中authority的值,当前缀是ROLE_时表示角色,否则是权限。
UserService.java
在启动类(AuthServerApplication.java)这里进行数据库的初始化,写入用户和角色数据,方便后续的测试:
注:内置了一个admin用户(密码admin,角色ROLE_ADMIN)和一个worker用户(密码worker,无角色)
WebSecurity的配置(WebSecurityConfig.java),前面的User、Role和UserService都是为这个配置做的准备:
认证中心的配置(AuthServerConfig.java):
注:@EnableAuthorizationServer和@EnableResourceServer开启了OAuth2的认证中心和资源服务器能力,身兼两职;
自定义授权类型“短信验证码”(SmsTokenGranter.java):
4、测试auth-server
为了方便测试,这里使用了Postman,官网:https://www.postman.com
认证中心auth-server启动后,可以从/oauth/token获取access token,就是JWT令牌。这里我们先用Postman测试一下令牌的获取,确保auth-server运转正常。建议大家在实际开发中,也先用第三方工具进行验证,因为不管是团队内部沟通还是跟外部交流,第三方工具出的测试结果更有说服力,更容易达成一致。
通过/oauth/token获取访问令牌,有多种方式。在AuthServerConfig.java中也可以看到,我们针对不同的客户端(OAuthClient)配置了多种GrantType,这里就分别测试一下。
GrantType: client_credentials,客户端凭据,这里所谓的凭据,就是AuthServerConfig.java中配置的客户端Id和secret。这个方式是用的客户端应用的身份,跟我们前面说的RBAC(基于角色的权限控制)里的用户、角色等是没关系的。
Url: http://localhost:8100/oauth/token
Method: POST
Params: grant_type=client_credentials
Authorization: Basic Auth,Username=service-one,Password=123456
GrantType: password,账号密码方式,提供用户的账号密码给auther-server进行用户认证,通过后返回包含用户账号和角色的JWT令牌。
Url: http://localhost:8100/oauth/token
Method: POST
Params: grant_type=password, username=admin,password=admin
Authorization: Basic Auth,Username=service-one,Password=123456
注意:Authorization跟client_credentials一样,也就是说先验证客户端的凭据,再验证用户的凭据。
GrantType: refresh_token,刷新令牌,我们用granttype=password测试时获得的refresh_token进行测试。
Url: http://localhost:8100/oauth/token
Method: POST
Params: grant_type=refresh_token,refresh_token=eyJhbGciOiJSUz...
Authorization: Basic Auth,Username=service-one,Password=123456
GrantType: sms_code,自定义认证,这里模拟的是短信验证码。微信、微博、支付宝等第三方登录,都可以按这个思路来实现。
Url: http://localhost:8100/oauth/token
Method: POST
Params: grant_type=sms_code,sms_code=123
Authorization: Basic Auth,Username=service-one,Password=123456
注:123是错误的sms_code,所以返回错误“SmsCode invalid!”,大家可以查看一下代码,看看正确的“短信验证码”是多少,随便把这个自定义认证方式多熟悉一下。
版权声明: 本文为 InfoQ 作者【xiaoboey】的原创文章。
原文链接:【http://xie.infoq.cn/article/86533fc8bd7197563e5dacd15】。文章转载请联系作者。
评论