如何将 Auth 服务与微服务架构中的其他服务解耦?
How to decouple Auth services from other services in Microservice Architecture?
我有一套微服务,其中一个负责身份验证。所有服务都使用共享库,例如flask_jwt_extended, and a shared secret key for validating the incoming requests (e.g. using jwt_required
decorator of the flask_jwt_extended ).
身份验证服务的主要端点是 UserLogin 和 UserLogout,诸如此类:
class UserLogin(Resource):
def __init__(self, *args, **kwargs):
self.parser = reqparse.RequestParser()
self.parser.add_argument('email', type=str, required=True)
self.parser.add_argument('password', type=str, required=True)
def post(self):
args = self.parser.parse_args()
email = args.get('email')
password = args.get('password')
user = User.query.filter_by(email=email).first()
if not user:
return jsonify({'message': 'User does not exist'})
if user.verify_hash(password):
access_token = create_access_token(identity=user.email)
return jsonify({'access_token': access_token})
else:
return jsonify({'message': 'Wrong credentials'})
class UserLogout(Resource):
@jwt_required
def post(self):
#Get the token and presist
jti = get_raw_jwt()['jti']
blocked_token = BlockedTokens(jti=jti)
db.session.add(blocked_token)
db.session.commit()
return jsonify({'message': 'logged out'})
然后在其他服务中,我使用 jwt_required
装饰器保护端点,它只是验证传入请求的令牌(没什么特别的):
class PostDetails(Resource):
@jwt_required
def get(self, post_id):
pass
当然,所有服务都共享同一个密钥:
app = app = Flask(__name__,)
app.config.from_mapping(JWT_SECRET_KEY=os.environ['JWT_SECRET_KEY'])
注销操作理想情况下应该如下:
- 将访问令牌存储在身份验证服务的数据库中。
- 对于每个请求,如果其令牌在黑名单中则阻止它。
我的问题是:
如何在不引入服务之间进一步耦合的情况下检查其他服务(除了 auth 服务)中被阻止的令牌?
是否可以进一步分离服务,即不共享任何库或密钥?
编辑:我已经在问题中添加了更多细节和代码片段,我希望它能得到更好的澄清和证明。
基于以上评论。
简短的回答是肯定的,这可能是身份验证服务的开销,但这是分离服务并将您的身份验证逻辑限制在同一服务中的最佳方式。
另一种方法是将令牌放入分布式缓存中,如果令牌被列入黑名单则对其进行验证。您只能将令牌保留在令牌到期时间段内的缓存中。假设你有 15 分钟的令牌过期时间,你将只检查缓存中最近 15 分钟内生成的令牌,其余令牌无论如何都已过期并且可以被删除。这将使缓存的大小保持较小并且可以更快地检查。此缓存服务可以在您的所有服务之间共享。
通常我们有网关服务(public端点)验证令牌,该服务可以调用缓存服务来检查令牌是否在缓存黑名单中。
我有一套微服务,其中一个负责身份验证。所有服务都使用共享库,例如flask_jwt_extended, and a shared secret key for validating the incoming requests (e.g. using jwt_required
decorator of the flask_jwt_extended ).
身份验证服务的主要端点是 UserLogin 和 UserLogout,诸如此类:
class UserLogin(Resource):
def __init__(self, *args, **kwargs):
self.parser = reqparse.RequestParser()
self.parser.add_argument('email', type=str, required=True)
self.parser.add_argument('password', type=str, required=True)
def post(self):
args = self.parser.parse_args()
email = args.get('email')
password = args.get('password')
user = User.query.filter_by(email=email).first()
if not user:
return jsonify({'message': 'User does not exist'})
if user.verify_hash(password):
access_token = create_access_token(identity=user.email)
return jsonify({'access_token': access_token})
else:
return jsonify({'message': 'Wrong credentials'})
class UserLogout(Resource):
@jwt_required
def post(self):
#Get the token and presist
jti = get_raw_jwt()['jti']
blocked_token = BlockedTokens(jti=jti)
db.session.add(blocked_token)
db.session.commit()
return jsonify({'message': 'logged out'})
然后在其他服务中,我使用 jwt_required
装饰器保护端点,它只是验证传入请求的令牌(没什么特别的):
class PostDetails(Resource):
@jwt_required
def get(self, post_id):
pass
当然,所有服务都共享同一个密钥:
app = app = Flask(__name__,)
app.config.from_mapping(JWT_SECRET_KEY=os.environ['JWT_SECRET_KEY'])
注销操作理想情况下应该如下:
- 将访问令牌存储在身份验证服务的数据库中。
- 对于每个请求,如果其令牌在黑名单中则阻止它。
我的问题是:
如何在不引入服务之间进一步耦合的情况下检查其他服务(除了 auth 服务)中被阻止的令牌?
是否可以进一步分离服务,即不共享任何库或密钥?
编辑:我已经在问题中添加了更多细节和代码片段,我希望它能得到更好的澄清和证明。
基于以上评论。
简短的回答是肯定的,这可能是身份验证服务的开销,但这是分离服务并将您的身份验证逻辑限制在同一服务中的最佳方式。
另一种方法是将令牌放入分布式缓存中,如果令牌被列入黑名单则对其进行验证。您只能将令牌保留在令牌到期时间段内的缓存中。假设你有 15 分钟的令牌过期时间,你将只检查缓存中最近 15 分钟内生成的令牌,其余令牌无论如何都已过期并且可以被删除。这将使缓存的大小保持较小并且可以更快地检查。此缓存服务可以在您的所有服务之间共享。
通常我们有网关服务(public端点)验证令牌,该服务可以调用缓存服务来检查令牌是否在缓存黑名单中。