身份验证
为 gRPC 服务配置身份验证,包括 TLS、JWT 和自定义认证
gRPC 支持各种身份验证机制来保护您的服务。身份验证可以在传输层(TLS)和应用层(凭证、令牌等)进行配置。
传输安全(TLS)
gRPC 强烈建议在生产环境服务中使用 TLS 以确保加密通信:
auth_service.proto
syntax = "proto3";package auth.v1;// Authentication serviceservice AuthService {// Authenticate user and return JWT tokenrpc Login(LoginRequest) returns (LoginResponse);// Validate and refresh JWT tokenrpc RefreshToken(RefreshTokenRequest) returns (RefreshTokenResponse);// Logout and invalidate tokenrpc Logout(LogoutRequest) returns (google.protobuf.Empty);}message LoginRequest {string email = 1;string password = 2;}message LoginResponse {string access_token = 1;string refresh_token = 2;int64 expires_in = 3;User user = 4;}
在您的服务器中配置 TLS:
server.py
import grpcfrom grpc import ssl_channel_credentialsimport auth_service_pb2_grpcdef create_secure_server():# Load TLS credentialsserver_credentials = grpc.ssl_server_credentials([(private_key, certificate_chain)])server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))auth_service_pb2_grpc.add_AuthServiceServicer_to_server(AuthServiceServicer(), server)# Listen on secure portserver.add_secure_port('[::]:443', server_credentials)return server
JWT 身份验证
使用 JWT 令牌进行无状态身份验证:
auth.proto
syntax = "proto3";package auth.v1;// JWT claims for user authenticationmessage JWTClaims {string user_id = 1;string email = 2;repeated string roles = 3;google.protobuf.Timestamp issued_at = 4;google.protobuf.Timestamp expires_at = 5;}
在您的服务中实现 JWT 身份验证:
auth_service.py
import grpcimport jwtfrom grpc import ServicerContextclass AuthServiceServicer(auth_service_pb2_grpc.AuthServiceServicer):def Login(self, request, context):# Validate credentialsuser = self.validate_credentials(request.email, request.password)if not user:context.set_code(grpc.StatusCode.UNAUTHENTICATED)context.set_details('Invalid credentials')return auth_service_pb2.LoginResponse()# Generate JWT tokenpayload = {'user_id': user.id,'email': user.email,'roles': user.roles,'exp': datetime.utcnow() + timedelta(hours=1)}access_token = jwt.encode(payload, JWT_SECRET, algorithm='HS256')return auth_service_pb2.LoginResponse(access_token=access_token,refresh_token=self.generate_refresh_token(user.id),expires_in=3600,user=user)
用于身份验证的拦截器
使用 gRPC 拦截器来处理所有方法的身份验证:
auth_interceptor.py
import grpcimport jwtfrom grpc import ServicerContextclass AuthInterceptor(grpc.ServerInterceptor):def __init__(self, jwt_secret, exempt_methods=None):self.jwt_secret = jwt_secretself.exempt_methods = exempt_methods or []def intercept_service(self, continuation, handler_call_details):method_name = handler_call_details.method# Skip authentication for exempt methodsif method_name in self.exempt_methods:return continuation(handler_call_details)# Extract metadatametadata = dict(handler_call_details.invocation_metadata)authorization = metadata.get('authorization', '')if not authorization.startswith('Bearer '):return self._unauthenticated_response()token = authorization[7:] # Remove 'Bearer ' prefixtry:# Validate JWT tokenpayload = jwt.decode(token, self.jwt_secret, algorithms=['HS256'])# Add user info to contexthandler_call_details = handler_call_details._replace(invocation_metadata=handler_call_details.invocation_metadata + (('user_id', payload['user_id']),('user_email', payload['email']),))return continuation(handler_call_details)except jwt.ExpiredSignatureError:return self._expired_token_response()except jwt.InvalidTokenError:return self._invalid_token_response()def _unauthenticated_response(self):def abort(ignored_request, context):context.set_code(grpc.StatusCode.UNAUTHENTICATED)context.set_details('Missing or invalid authorization header')return grpc.unary_unary_rpc_method_handler(abort)
API 密钥身份验证
实现基于 API 密钥的身份验证:
api_key.proto
syntax = "proto3";package auth.v1;message ApiKeyRequest {string api_key = 1;string service_name = 2;}message ApiKeyResponse {bool valid = 1;string client_id = 2;repeated string permissions = 3;google.protobuf.Timestamp expires_at = 4;}
服务器实现:
api_key_auth.py
class ApiKeyAuthInterceptor(grpc.ServerInterceptor):def __init__(self, api_key_store):self.api_key_store = api_key_storedef intercept_service(self, continuation, handler_call_details):metadata = dict(handler_call_details.invocation_metadata)api_key = metadata.get('x-api-key', '')if not api_key:return self._unauthorized_response('API key required')# Validate API keykey_info = self.api_key_store.get(api_key)if not key_info or key_info.is_expired():return self._unauthorized_response('Invalid or expired API key')# Add client info to contexthandler_call_details = handler_call_details._replace(invocation_metadata=handler_call_details.invocation_metadata + (('client_id', key_info.client_id),('permissions', ','.join(key_info.permissions)),))return continuation(handler_call_details)
OAuth2 集成
与 OAuth2 提供商集成:
oauth2_auth.py
import requestsfrom google.oauth2 import id_tokenfrom google.auth.transport import requests as google_requestsclass OAuth2Interceptor(grpc.ServerInterceptor):def __init__(self, google_client_id):self.google_client_id = google_client_iddef intercept_service(self, continuation, handler_call_details):metadata = dict(handler_call_details.invocation_metadata)auth_header = metadata.get('authorization', '')if not auth_header.startswith('Bearer '):return self._unauthorized_response()token = auth_header[7:]try:# Verify Google ID tokenidinfo = id_token.verify_oauth2_token(token, google_requests.Request(), self.google_client_id)# Add user info to contexthandler_call_details = handler_call_details._replace(invocation_metadata=handler_call_details.invocation_metadata + (('user_id', idinfo['sub']),('user_email', idinfo['email']),('user_name', idinfo.get('name', '')),))return continuation(handler_call_details)except ValueError:return self._invalid_token_response()
客户端身份验证
在客户端配置身份验证:
client.py
import grpc# TLS with JWTdef create_authenticated_channel(server_address, jwt_token):credentials = grpc.ssl_channel_credentials()channel = grpc.secure_channel(server_address, credentials)# Add JWT token to all requestsdef jwt_interceptor(continuation, client_call_details):metadata = list(client_call_details.metadata or [])metadata.append(('authorization', f'Bearer {jwt_token}'))client_call_details = client_call_details._replace(metadata=metadata)return continuation(client_call_details)intercepted_channel = grpc.intercept_channel(channel, jwt_interceptor)return intercepted_channel# API Key authenticationdef create_api_key_channel(server_address, api_key):credentials = grpc.ssl_channel_credentials()channel = grpc.secure_channel(server_address, credentials)def api_key_interceptor(continuation, client_call_details):metadata = list(client_call_details.metadata or [])metadata.append(('x-api-key', api_key))client_call_details = client_call_details._replace(metadata=metadata)return continuation(client_call_details)intercepted_channel = grpc.intercept_channel(channel, api_key_interceptor)return intercepted_channel
基于角色的访问控制
实现用于细粒度权限控制的 RBAC:
rbac.proto
syntax = "proto3";package auth.v1;message Permission {string resource = 1;string action = 2;}message Role {string name = 1;repeated Permission permissions = 2;}message UserRoles {string user_id = 1;repeated string role_names = 2;}
RBAC 拦截器实现:
rbac_interceptor.py
class RBACInterceptor(grpc.ServerInterceptor):def __init__(self, permission_store):self.permission_store = permission_storedef intercept_service(self, continuation, handler_call_details):# Get user info from context (added by auth interceptor)metadata = dict(handler_call_details.invocation_metadata)user_id = metadata.get('user_id')if not user_id:return self._unauthorized_response()# Check permissions for the methodmethod_name = handler_call_details.methodrequired_permission = self._get_required_permission(method_name)if required_permission and not self._has_permission(user_id, required_permission):return self._forbidden_response()return continuation(handler_call_details)def _has_permission(self, user_id, permission):user_roles = self.permission_store.get_user_roles(user_id)for role in user_roles:if permission in role.permissions:return Truereturn False
gRPC 的灵活身份验证系统允许您实现安全、可扩展的身份验证模式,这些模式可以在不同的环境和用例中工作。