跳到主要内容
版本:4.1.x

OAuth2应用集成

本文介绍OAuth2应用如何与MaxKey进行集成。

认证流程

采用Authorization Code获取Access Token的授权验证流程又被称为Web Server Flow,适用于所有Server端的应用。其调用流程示意图如下: sso_oauth

对于应用而言,其流程由获取Authorization Code和通过Authorization Code获取Access Token这2步组成。

1.引导需要授权的用户到如下地址:

http://sso.maxkey.top/sign/authz/oauth/v20/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI 

2.页面跳转至

YOUR_REGISTERED_REDIRECT_URI/?code=CODE

3.换取Access Token

http://sso.maxkey.top/sign/authz/oauth/v20/token?client_id=YOUR_CLIENT_ID&client_secret=YOUR _SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE

返回值

{ "access_token":"SlAV32hkKG", "remind_in ":3600, "expires_in":3600 }

应用注册

应用在MaxKey管理系统进行注册,注册的配置信息如下

sso_oauth_conf

API接口标准

接口 说明 详细说明
/authz/oauth/v20/authorize 请求用户授权Token http://sso.maxkey.top/sign接收app sso认证请求,
client_id为需要认证的应用的id;
/authz/oauth/v20/token 获取授权过的 Access Token 后台应用获取 code ,调用接口进行 code 校验;
校验成功获取访问 token
/api/oauth/v20/me 授权用户信息查询接口 通过访问 token 获取登录用户信息

授权接口

/authz/oauth/v20/authorize

请求用户授权Token

接口名称 请求用户授权Token
url http://sso.maxkey.top/sign/authz/oauth/v20/authorize
请求方式 http get/post
请求参数
参数 说明
client_id 注册应用时分配的client_id。
redirect_uri 应用回调地址,注册时需要配置
grant_type授权类型。
etc param其他参数。

响应返回app应用程序,包含请求参数如下:

http://app.maxkey.org/app/callback?code =PQ7q7W91a-oMsCeLvIaQm6bTrgtp7

code用于调用/authz/oauth/token,接口获取授权后的访问token。

令牌接口

/authz/oauth/v20/token

通过/authz/oauth/v20/token用code换取访问token

接口名称 token 接口
url http://sso.maxkey.top/sign/authz/oauth/v20/token
请求方式 http get/post
请求参数
参数 说明
client_id 注册应用时分配的client_id。
client_secret 注册应用时分配的client_secret
redirect_uri 应用回调地址,注册时需要配置
code调用authz/oauth/v20/authorize获得的code值。
grant_type授权类型。Grant type
username当grant_type=password时,此参数表示直接认证用户名。
password当grant_type=password时,此参数表示直接认证用户密码。
etc param其他参数

实际请求如下:

The actual request might look like:
POST /authz/oauth/v20/token token HTTP/1.1
Host: sso.maxkey.org/openapi
Content-Type: application/x-www-form-urlencoded
code= PQ7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=QPKKKSADFUP876&
client_secret=client_secret&
redirect_uri=http://app.maxkey.org/app/callback

返回数据

A successful response to this request contains the following fields:

access_token用该token能调用SSO的API

成功返回JSON数据,如下:

{ 
"access_token":"token_id",
"id_token":"id_token"
}

用户属性接口

/api/oauth/v20/me

接口名称 token 接口
url http://sso.maxkey.top/sign/api/oauth/v20/me
请求方式 http get/post
请求参数
参数 说明
access_token 调用sso/ token获得的token值。

实际请求如下:

POST /oauth/ userinfo HTTP/1.1
Host: sso.maxkey.org/openapi
Content-Type: application/x-www-form-urlencoded
access_token= PQ7q7W91a-oMsCeLvIaQm6bTrgtp7

返回数据/ response data

成功返回JSON数据,如下:

{
"userid":"zhangs"
}

zhangs是认证的用户ID

OAuth认证接口属性列表

属性名(Attribute) 描述 数据类型
uiduid字符串

OAuth2.0 错误码

MaxKey OAuth2.0实现中,授权服务器在接收到验证授权请求时,会按照OAuth2.0协议对本请求的请求头部.请求参数进行检验,若请求不合法或验证未通过,授权服务器会返回相应的错误信息,包含以下几个参数:

error: 错误码

error_description: 错误的描述信息

错误信息的返回方式有两种:

当请求授权Endpoint:http://sso.maxkey.top/sign/authz/oauth/v20/authorize 时出现错误,返回方式是:跳转到redirect_uri,并在uri 的query parameter中附带错误的描述信息。

当请求access token endpoint:http://sso.maxkey.top/sign/authz/oauth/v20/token 时出现错误,返回方式:返回JSON文本。

例如:

{
"error":"unsupported_response_type",
"error_description":"不支持的 ResponseType."
}

OAuth2.0错误响应中的错误码定义如下表所示:

编号错误码(error)描述(error_description)
1empty_client_id参数client_id为空
2empty_client_secret参数client_secret为空
3empty_redirect_uri参数redirect_uri为空
4empty_response_type参数response_type为空
5empty_codecode为空
6app_unsupport_sso应用不支持sso登录
7app_unsupport_oauth应用不支持OAuth认证
8invalid_client_id非法的client_id
9invalid_response_type非法的response_type
10invalid_scope非法的scope
11invalid_grant_type非法的grant_type
12redirect_uri_mismatch非法的redirect_uri
13unsupported_response_type不支持传递的response_type
14invalid_code非法的code
15unsupported_refresh_token不支持refresh_token的方式
16access_token_expriseaccess_token过期
17invalid_access_token非法的access_token
18invalid_refresh_token非法的refresh_token
19refresh_token_expriserefresh_token过期

OAuth2客户端集成

本文使用JAVA WEB程序为例

引入依赖包

gson-2.2.4.jar
maxkey-client-sdk.jar
nimbus-jose-jwt-8.10.jar
commons-codec-1.9.jar
commons-io-2.2.jar
commons-logging-1.1.1.jar

认证授权

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ page language="java" import="org.maxkey.client.oauth.oauth.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.builder.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.builder.api.MaxkeyApi20" %>
<%@ page language="java" import="org.maxkey.client.oauth.model.Token" %>

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+path+"/";

String callback="http://oauth.demo.maxkey.top:8080/demo-oauth/oauth20callback.jsp";
OAuthService service = new ServiceBuilder()
.provider(MaxkeyApi20.class)
.apiKey("b32834accb544ea7a9a09dcae4a36403")
.apiSecret("E9UO53P3JH52aQAcnLP2FlLv8olKIB7u")
.callback(callback)
.build();
Token EMPTY_TOKEN = null;
String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN);

request.getSession().setAttribute("oauthv20service", service);

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>OAuth 2.0 SSO</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">

</head>

<body>
<a href="<%=authorizationUrl%>&approval_prompt=auto">oauth 2.0 sso</a>
</body>
</html>

获取令牌及用户信息

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page language="java" import="org.maxkey.client.oauth.oauth.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.builder.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.builder.api.MaxkeyApi20" %>
<%@ page language="java" import="org.maxkey.client.oauth.model.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.*" %>
<%@ page language="java" import="org.maxkey.client.oauth.domain.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

OAuthService service = (OAuthService)request.getSession().getAttribute("oauthv20service");
if(service == null){
String callback="http://oauth.demo.maxkey.top:8080/demo-oauth/oauth20callback.jsp";
service = new ServiceBuilder()
.provider(MaxkeyApi20.class)
.apiKey("b32834accb544ea7a9a09dcae4a36403")
.apiSecret("E9UO53P3JH52aQAcnLP2FlLv8olKIB7u")
.callback(callback)
.build();
}

Token EMPTY_TOKEN = null;
Verifier verifier = new Verifier(request.getParameter("code"));
Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);

OAuthClient restClient=new OAuthClient("http://sso.maxkey.top/sign/api/oauth/v20/me");
UserInfo userInfo=restClient.getUserInfo(accessToken.getAccess_token());

%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>OAuth V2.0 Demo</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="OAuth V2.0 Demo">
<link rel="shortcut icon" type="image/x-icon" href="<%=basePath %>/images/favicon.ico"/>
<script type="text/javascript" src="<%=basePath %>/jquery-3.5.0.min.js"></script>
<script type="text/javascript" src="<%=basePath %>/jsonformatter.js"></script>
<link type="text/css" rel="stylesheet" href="<%=basePath %>/demo.css"/>
</head>
<body>
<div class="container">
<table class="datatable">
<tr>
<td colspan="2" class="title">OAuth V2.0 Demo</td>
</tr>
<tr>
<td width="50%">OAuth V2.0 Logo</td>
<td width="50%"> <img src="<%=basePath %>/images/oauth-2-sm.png" width="124px" height="124px"/></td>
</tr>
<tr>
<td>Login</td>
<td><%=userInfo.getUsername() %></td>
</tr>
<tr>
<td>DisplayName</td>
<td><%=userInfo.getDisplayName() %></td>
</tr>
<tr>
<td>Department</td>
<td><%=userInfo.getDepartment() %></td>
</tr>
<tr>
<td>JobTitle</td>
<td><%=userInfo.getJobTitle() %></td>
</tr>
<tr>
<td>email</td>
<td><%=userInfo.getEmail() %></td>
</tr>
<tr>
<td>ResponseString</td>
<td style="word-wrap: break-word;">
<textarea cols="68" rows="20" v-model="text2"><%=userInfo.getResponseString() %></textarea>
</td>
</tr>
</table>
<script type="text/javascript">
FormatTextarea();
</script>
</div>
</body>
</html>

OAuth2 PASSWORD模式

本文使用JAVA 程序为例

package org.maxkey.client.oauth.test;

import org.maxkey.client.http.Response;
import org.maxkey.client.oauth.builder.api.MaxkeyPasswordApi20;
import org.maxkey.client.oauth.model.OAuthConfig;
import org.maxkey.client.oauth.model.Token;
import org.maxkey.client.oauth.oauth.OAuthPasswordService;

public class MaxkeyPasswordDemo {
/**
* @param args
*/
public static void main(String[] args) {
String accessTokenUrl="http://sso.maxkey.top/sign/authz/oauth/v20/token";
String clientId = "b32834accb544ea7a9a09dcae4a36403";
String clientSerect = "E9UO53P3JH52aQAcnLP2FlLv8olKIB7u";

String callback = "http://oauth.demo.maxkey.top:8080/demo-oauth/oauth20callback.jsp";
String responseType ="token";
String approvalprompt = "auto";

OAuthConfig oauthServiceConfig=new OAuthConfig(clientId,clientSerect,callback);
MaxkeyPasswordApi20 passwordApi20=new MaxkeyPasswordApi20(accessTokenUrl);
OAuthPasswordService oAuthPasswordService=new OAuthPasswordService(oauthServiceConfig,passwordApi20);
Token accessToken = null;
Response response = null;
accessToken = oAuthPasswordService.getAccessToken("admin", "maxkey");
}
}

详细见请参考

https://github.com/MaxKeyTop/MaxKey-Client-sdk/blob/master/src/test/java/org/maxkey/client/oauth/test/MaxkeyPasswordDemo.java