全部产品

统一鉴权

更新时间:2019-12-11 23:37:16

移动API网关统一鉴权功能可以帮助用户在网关层面构建一个统一的鉴权逻辑,使得所有经过网关的API请求,可以提前完成权限的校验、身份信息的置换。请求通过API网关以后,已经是受信状态,后端业务便无需再参与到鉴权逻辑中。

统一鉴权配置流程

通过以下步骤使用统一鉴权功能:

  1. 用户必须提供一个用于鉴权的后端服务,此鉴权服务需要实现约定的restful接口;
  2. 在应用管理页,创建一个独立的应用A,它只用于维护提供鉴权服务的机器组;API网关需要处理一次鉴权时,便是通过A路由到可用鉴权服务机器上;
  3. 对于需要使用鉴权服务的应用B,则需要配置开启使用鉴权,并使用应用A作为自己的鉴权服务提供者;还需要配置相应的鉴权服务访问路径、授权缓存时间等参数;
  4. 对于应用B下的API,则需要开启 是否需要鉴权 开关为 ,然后发布API上线;
  5. 请求此API时,携带指定的 x-emas-gw-auth-ticket 头(此header头名称为default值,可以在控制台自定义),就能使用鉴权能力了;
  6. API网关会根据 x-emas-gw-auth-ticket 获取到请求的身份凭证,调用鉴权服务进行鉴权,获得鉴权的结果;若鉴权通过,且鉴权结果中携带了额外的身份信息,API网关会把这份信息,序列化为JSON字符串,携带在请求的 x-emas-gw-authorization 中,继续转发请求到业务后端;
  7. 业务后端接收到请求,从请求header中读取 x-emas-gw-authorization 头部,便可拿到鉴权后的身份信息了;

鉴权服务接口约定

用户需要实现一个鉴权服务,API网关在处理需要鉴权的请求时,会请求这个鉴权服务,获得鉴权信息。因此,这个鉴权服务应当和API网关达成一些约定。

  • 请求:API网关请求鉴权服务时,会携带 x-emas-gw-auth-ticketx-emas-gw-apix-emas-gw-v 在body中,以JSON格式,发送请求,如:
  1. POST ${auth-server-ip}/auth
  2. {
  3. "x-emas-gw-auth-ticket": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  4. "x-emas-gw-api": api,
  5. "x-emas-gw-v": v
  6. }

其中:

  • x-emas-gw-auth-ticket:端上通过请求header携带的鉴权凭证信息;
  • x-emas-gw-api:端上通过
  • x-emas-gw-v:

  • 响应:鉴权服务处理鉴权后,应返回如下字段:

  1. {
  2. "success": true/false,
  3. "ttl": 10,
  4. "authorization": {
  5. "customKey": "costumValue",
  6. ...
  7. }
  8. }

其中:

  • success:布尔值,表示鉴权是否通过;
  • ttl:缓存时间,不为0时生效;API网关会缓存鉴权结果,且只在鉴权通过时缓存结果;若次字段返回0或者不返回此字段,则缓存时间以控制台设置的统一缓存时间为准;
  • authorization:业务鉴权后可以在此字段中返回鉴权得到的身份信息,API网关会把此信息序列化为JSON字符串,携带在请求中转发到后端业务;

鉴权流程示意图

统一鉴权流程图

开发鉴权服务应用

用户需要自行提供提供鉴权服务的应用,如协议所述,这个应用需要实现:接收请求,获得相关参数,做鉴权处理,并返回相关鉴权结果。

如一个JAVA实现的版本:

  1. @Data
  2. public class AuthRequest implements Serializable {
  3. @JsonProperty("x-emas-gw-auth-ticket")
  4. private String authTicket;
  5. @JsonProperty("x-emas-gw-api")
  6. private String apiName;
  7. @JsonProperty("x-emas-gw-v")
  8. private String apiVersion;
  9. }
  10. @PostMapping("/emas/auth")
  11. @ResponseBody
  12. public Object getAuth(@RequestBody AuthRequest authRequest) throws Exception {
  13. logger.info("ticket: {}, api: {}, version: {}", authRequest.getAuthTicket(), authRequest.getApiName(), authRequest.getApiVersion());
  14. Map<String, Object> result = new HashMap<String, Object>();
  15. Map<String, String> authorization = new HashMap<String, String>();
  16. authorization.put("uid", "12345");
  17. authorization.put("user_name", "zhouzhuo");
  18. result.put("success", true);
  19. result.put("ttl", 30);
  20. result.put("authorization", authorization);
  21. return result;
  22. }

控制台添加鉴权服务应用

上述提供鉴权服务的应用发布以后,这个应用所在的机器组也应当通过API网关来维护。在控制台添加应用:

添加鉴权应用

然后在该应用管理页,添加上提供服务的ip组和端口。添加ip、端口,等待30秒左右,确认健康检查状态为正常。

控制台开启鉴权配置

进入应用管理页,对于需要使用鉴权服务的应用,点击配置,填上相关字段。

配置鉴权

控制台更新API配置

应用做了鉴权配置之后,归属于这个应用下的API还需要开启 需要鉴权 ,才会真正地请求鉴权。

注意,变更之后,需要发布生效。

开启鉴权

业务后端获取鉴权身份信息

如上配置之后,端上发起请求后,API网关会获取请求header中的凭证信息,去请求 鉴权应用 ,对凭证做鉴权。鉴权通过后, 鉴权应用 会返回鉴权结果和相关业务自定义的身份信息,API网关会把这个信息序列化为JSON,携带在发往 业务后端应用 的请求header中。所以 业务后端应用 在接收到请求时,需要这么获取身份信息:

  1. @RequestMapping("/test")
  2. @ResponseBody
  3. public String test(HttpServletRequest request, HttpServletResponse response) throws IOException {
  4. String authorizationJSON = request.getHeader("x-emas-gw-authorization");
  5. JSONObject authorization = JSON.parseObject(authorizationJSON);
  6. String customValue1 = authorization.getString("customKey1");
  7. ...
  8. }

Android端请求携带凭证信息

Android端上发起需要鉴权的请求时,在header中携带凭证信息:

  1. MtopRequest mtopRequest = new MtopRequest();
  2. mtopRequest.setApiName(api);
  3. mtopRequest.setVersion(v);
  4. mtopRequest.setData(data);
  5. mtopBuilder = mtopInstance.build(mtopRequest, "600000@taobao_android_7.7.3");
  6. mtopBuilder.setCustomDomain(EmasInit.getInstance().mAPIDoman);
  7. mtopBuilder.addListener(new OnFinishListener());
  8. mtopBuilder.setRequestProrocolVersion(MtopProtocolVersion.V6);
  9. mtopBuilder.setContentType(MtopContentType.JSON);
  10. mtopBuilder.reqMethod(MethodEnum.POST);
  11. Map<String, String> headers = new HashMap<>();
  12. headers.put("x-emas-gw-auth-ticket", "sample-login-ticket");
  13. mtopBuilder.headers(headers);

若鉴权不通过,应从以下错误码判断,然后进行响应业务处理:

  1. private class OnFinishListener implements MtopFinishListener {
  2. public void onFinished(MtopFinishEvent mtopFinishEvent, Object o) {
  3. MtopResponse response = mtopFinishEvent.mtopResponse;
  4. if (response != null) {
  5. Log.i("response", response.toString());
  6. if ("SUCCESS".equals(response.getRetCode())) {
  7. Log.i("response", "请求成功");
  8. } else {
  9. if ("FAIL_SYS_AUTH_PARAM_MISSED".equals(response.getRetCode())) {
  10. Log.e("errorMessage", "客户端请求缺少鉴权参数,鉴权失败");
  11. }
  12. if ("FAIL_SYS_AUTH_FAILED".equals(response.getRetCode())) {
  13. Log.e("errorMessage", "请求鉴权服务错误,鉴权失败");
  14. }
  15. if ("FAIL_SYS_AUTH_FAULT".equals(response.getRetCode())) {
  16. Log.e("errorMessage", "鉴权配置错误,鉴权失败");
  17. }
  18. if ("FAIL_SYS_UNAUTH_API_ERROR".equals(response.getRetCode())) {
  19. Log.e("errorMessage", "业务鉴权不通过,鉴权失败");
  20. }
  21. }
  22. }
  23. }
  24. }

iOS端请求携带凭证信息

iOS端上发起需要鉴权的请求时,在header中携带以下信息:

  1. MtopExtRequest* request = [[MtopExtRequest alloc] initWithApiName: @"mtop.test.normal" apiVersion: @"1.0"];
  2. [request setCustomHost:domain];
  3. [request setProtocolType:MtopProtocolTypeEmas];
  4. [request addHttpHeader:@"sample-auth-ticket" forKey:@"x-emas-gw-auth-ticket"];
  5. ...

若鉴权不通过,应从以下错误码判断,然后进行响应业务处理:

  1. if (response.error) {
  2. NSLog(@"请求失败: %@", response.error);
  3. if ([response.error.code isEqualToString:@"FAIL_SYS_AUTH_PARAM_MISSED"]) {
  4. NSLog(@"客户端请求缺少鉴权参数,鉴权失败");
  5. }
  6. if ([response.error.code isEqualToString:@"FAIL_SYS_AUTH_FAILED"]) {
  7. NSLog(@"请求鉴权服务错误,鉴权失败");
  8. }
  9. if ([response.error.code isEqualToString:@"FAIL_SYS_AUTH_FAULT"]) {
  10. NSLog(@"鉴权配置错误,鉴权失败");
  11. }
  12. if ([response.error.code isEqualToString:@"FAIL_SYS_UNAUTH_API_ERROR"]) {
  13. NSLog(@"业务鉴权不通过,鉴权失败");
  14. }
  15. }