什么是OAuth2认证
简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
而IdentityServer4就是一个开源的OAuth2认证系统。网关与IdentityServer4集成之后,我们可以避免为内部的每个微服务集成IdentityServer4,可以避免很多重复的工作,而这也是网关的一个重要优势。
新建IdentityServer4服务
1新增WebApi,并引用Nuget包IdentityServer4
2.新增校验证书,其中的证书文件通过openssl创建
2.1安装生成证书程序:https://slproweb.com/products/Win32OpenSSL.html(对应操作系统)
2.2找到openssl安装位置生成证书,Country Name (2 letter code) [AU]:跳过所有步骤
代码语言:javascript复制openssl req -newkey rsa:2048 -nodes -keyout chester.key -x509 -days 365 -out chester.cer
代码语言:javascript复制openssl pkcs12 -export -in chester.cer -inkey chester.key -out chester.pfx
3.新增配置信息
代码语言:javascript复制public class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "我的第一个API")
{
UserClaims =
{
JwtClaimTypes.Audience
},
Scopes = new List<string>
{
"api"
},
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId="client",//定义客户端ID
ClientSecrets=
{
new Secret("secret".Sha256())//定义客户端秘钥
},
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,//授权方式为用户密码模式授权,类型可参考GrantTypes枚举
AllowedScopes={ "api" }//允许客户端访问的范围
}
};
}
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[] { new ApiScope("api") };
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new IdentityResource[]
{
new IdentityResources.OpenId()
};
}
}
4.注入IdentityServer4
代码语言:javascript复制public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()//注册服务
//.AddDeveloperSigningCredential()
.AddSigningCredential(new X509Certificate2("chester.pfx","123456") )
.AddInMemoryApiResources(Config.GetApiResources())//配置类定义的授权范围
.AddInMemoryClients(Config.GetClients())//配置类定义的授权客户端
.AddInMemoryApiScopes(Config.ApiScopes)
.AddTestUsers(new List<TestUser> { new TestUser { Username = "Admin", Password = "123456", SubjectId = "001", IsActive = true } });//模拟测试用户,这里偷懒了,用户可以单独管理,最好不要直接在这里New
services.AddControllers();
}
5.开启IdentityServer4中间件
代码语言:javascript复制app.UseIdentityServer();//添加中间件
代码语言:javascript复制
6.然后启动IdentityServer4服务
配置Envoy
我们需要用到Envoy的envoy.filters.http.jwt_authn,需要注意的有以下几点
- Envoy的过滤器加载是自上而下的,因此我们需要将此过滤器放到envoy.filters.http.router前
- 另外我们需要在配置文件中配置jwt的jwks地址/.well-known/openid-configuration/jwks,jwks是JSON Web密钥集—一种用于共享公钥的JSON表示法,用于验证JWT签名
- 并且我们需要配置ids4服务的cluster。
具体配置如下,需要注意的地方已标红
代码语言:javascript复制admin:
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9902
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
scheme_header_transformation:
scheme_to_overwrite: http
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: 192.168.43.94
cluster: service_envoyproxy_io
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
jwt_provider:
issuer: "http://192.168.43.94:7000"
audiences:
- "api1"
forward: true
remote_jwks:
http_uri:
uri: "http://192.168.43.94:7000/.well-known/openid-configuration/jwks"
cluster: jwtserver
timeout: 5s
rules:
- match:
prefix: "/"
requires:
provider_name: jwt_provider
- name: envoy.filters.http.router
clusters:
- name: jwtserver
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: jwtserver
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 7000
- name: service_envoyproxy_io
connect_timeout: 30s
type: strict_dns
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5000
启动envoy
代码语言:javascript复制docker run --rm -it -p 9902:9902 -p 10000:10000 -v D:/gateway/envoy/config/static/:/etc/envoy/ -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev -c /etc/envoy/envoy-jwt.yaml
验证jwt
我们直接访问http://192.168.43.94:10000/Name,不携带token,可以看到请求被拒绝,返回401
下面我们调用ids4的/connect/token接口获取token
将获取到的token放到Name接口的Header里,再次调用成功!!!
至此,我们通过Envoy IdentityServer4实现了网关的JWT认证,可以节省内部微服务与IdentityServer4重复的集成工作,实现了统一处理认证逻辑。