了解有关Java应用程序和Oracle Identity Cloud Service之间的验证的信息

您已准备好了解Java Web 应用程序与Oracle Identity Cloud Service之间的验证。其中包括了解以下内容:

  • Oracle Identity Cloud Service为Java SDK 支持的三路验证流

  • 将 SDK 与Java应用程序一起使用时,用于向Oracle Identity Cloud Service进行验证

  • Java SDK 的方法和功能

了解有关三路验证流的信息

Oracle Identity Cloud Service支持Java SDK 的三路验证流。在此流中,用户直接与Oracle Identity Cloud Service交互。用户登录后,Oracle Identity Cloud Service将发出一个用户访问标记的 SDK 交换的授权代码。Java Web 应用程序使用该访问标记向用户授予对应用程序中受保护资源的访问权限。三路流使用授权代码授权类型。

为提高安全性,Oracle建议您使用三路流将Java Web 应用程序与Oracle Identity Cloud Service集成以进行验证。通过使用授权代码授权类型,您还可以访问由Oracle Identity Cloud Service保护的其他应用程序,而无需重新验证。

了解将 SDK 与Java应用程序配合使用的主要用例

Java Web 应用程序实施了两种用例:一个用于验证用户,另一个用于访问登录用户的详细信息。

以下数据流图表说明了 Web 浏览器、Web 应用程序和Oracle Identity Cloud Service之间每种用例的事件、调用和响应流。

用例# 1:验证用户

数据流将以下方式进行:

  1. 用户请求受保护的资源。

  2. 验证模块使用 SDK 生成Oracle Identity Cloud Service的请求授权代码 URL,并将此 URL 作为重定向响应发送到 Web 浏览器。

  3. Web 浏览器将调用 URL。

  4. 此时将显示Oracle Identity Cloud Service登录 页。

  5. 用户提交其Oracle Identity Cloud Service登录身份证明。

  6. 用户登录后,Oracle Identity Cloud Service为该用户创建一个会话并发出授权代码。

  7. Web 应用程序使后端(或服务器到服务器)调用可交换访问标记的授权代码。

  8. Oracle Identity Cloud Service发布访问标记和 id 标记。

  9. 会话已建立,用户将重定向到 页。

  10. 此时将显示 Web 应用程序的 页。

用例# 2:获取有关用户的详细信息

数据流将以下方式进行:

  1. 用户请求/myProfile资源。

  2. Web 应用程序使用Oracle Identity Cloud Service的 SDK 来验证 ID 标记。

  3. 从 Id 标记验证返回的数据包含 JSON 对象格式的用户详细信息。

  4. The My Profile page renders the JSON object as HTML content.

了解方法和函数

Java SDK 是一个将作为 Web 应用程序库加载的 JAR 文件。此 JAR 文件需要以下第三方库,您也必须将其加载到库中:

Java SDK zip 文件包含 SDK 所需的以下第三方库。您可以将它们加载到应用程序中。

  • ASM 帮助器 Minidev 1.0.2

  • Apache Commons 集合4.1

  • Apache Commons Lang 3.7

  • JSON 小和快速语法分析器2.3

  • Nimbus LangTag 1.4.3

  • Nimbus JOSE + JWT 5.14

  • 使用OpenID Connect Extensions 5.30的OAuth 2.0 SDK

Oracle提供了示例Java Web 应用程序,用于演示如何使用Java SDK。此应用程序是使用 Servlet 技术构建的,用于简化学习体验,了解Java SDK 的工作方式。应用程序使用 Maven 获取所有库并生成 Web 应用程序资源(WAR)文件。

Java SDK 需要一个使用Oracle Identity Cloud Service连接信息加载的HashMap对象实例。Java Web 应用程序将此HashMap实例作为ConnectionOptions.java类中的类属性实施。

//Instance of a HashMap.
    private Map<String,Object> options = new HashMap<>();
  
public ConnectionOptions(){
        this.options = new HashMap<>();
}
  
public Map<String,Object> getOptions(){
        //Adding Oracle Identity Cloud Service connection parameters to the HashMap instance.
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_HOST, "identity.oraclecloud.com");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_PORT, "443");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID, "123456789abcdefghij");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET, "abcde-12345-zyxvu-98765-qwerty");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT, "idcs-abcd1234");
        this.options.put(Constants.AUDIENCE_SERVICE_URL, "https://idcs-abcd1234.identity.oraclecloud.com");
        this.options.put(Constants.TOKEN_ISSUER, "https://identity.oraclecloud.com/");
        this.options.put(Constants.TOKEN_CLAIM_SCOPE, "urn:opc:idm:t.user.me openid");
        this.options.put("SSLEnabled", "true");
        this.options.put("redirectURL", "http://localhost:8080/callback");
        this.options.put("logoutSufix", "/oauth2/v1/userlogout");
        this.options.put(Constants.CONSOLE_LOG, "True");
        this.options.put(Constants.LOG_LEVEL, "DEBUG");
        return this.options;
    }

下面是此 SDK 的每个必需属性的简要说明:

名称 说明
IDCSTokenAssertionConfiguration.IDCS_HOST Oracle Identity Cloud Service实例的域后缀。
IDCSTokenAssertionConfiguration.IDCS_PORT Oracle Identity Cloud Service实例保留的 HTTPS 端口号(通常为443)。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID 在Identity Cloud Service控制台中注册Java Web 应用程序后生成的客户机 ID 的值。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET 在Identity Cloud Service控制台中注册Java Web 应用程序后生成的客户机密钥的值。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT Oracle Identity Cloud Service实例的域前缀。此前缀通常是类似于idcs-abcd1234的值。
Constants.AUDIENCE_SERVICE_URL Oracle Identity Cloud Service实例的全限定域名 URL。
Constants.TOKEN_ISSUER 对于此属性,Oracle建议保留值https://identity.oraclecloud.com
Constants.TOKEN_CLAIM_SCOPE

范围控制应用程序可代表Oracle Identity Cloud Service用户访问或处理的数据。

如果应用程序使用 SDK 对用户进行验证,则范围是openid。如果应用程序还使用 SDK 获取有关用户的详细信息,则范围为urn:opc:idm:t.user.me openid

SSLEnabled 指示Oracle Identity Cloud Service是响应 HTTPS 请求还是 HTTP 请求。对于此属性,Oracle建议保留值true
Constants.CONSOLE_LOG 启用 SDK 日志。
Constants.LOG_LEVEL 指示 SDK 的日志级别。

应用程序同时使用logoutSufixredirectURL属性来避免对这些值进行硬代码。SDK 不需要它们。

Java Web 应用程序实施AuthServlet类,该类映射/auth URL。当用户决定使用Oracle Identity Cloud Service进行验证时,Web 浏览器会向此 URL 发出请求。AuthServlet类将初始化Authentication Manager对象,使用Java SDK 生成Oracle Identity Cloud Service的授权代码 URL,然后将 Web 浏览器重定向到此 URL。

public class AuthServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //Configuration object instance with the parameters loaded.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
	String redirectUrl = (String)options.get("redirectURL");
        String scope = (String)options.get(Constants.TOKEN_CLAIM_SCOPE);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Using Authentication Manager to generate the Authorization Code URL, passing the
        //application's callback URL as parameter, along with code value and code parameter.
        String authzURL = am.getAuthorizationCodeUrl(redirectUrl, scope, "1234", "code");
        //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
        response.sendRedirect(authzURL);
    }
}

以下参数用于生成授权代码 URL:

名称 说明
redirectUrl 用户登录后,Oracle Identity Cloud Service会将用户的 Web 浏览器重定向到此 URL。此 URL 必须与您将为Identity Cloud Service控制台中的可信应用程序配置的 URL 匹配。有关为Java Web 应用程序指定重定向 URL 的详细信息,请参阅注册Java应用程序。
scope 验证的OAuth或OpenID连接范围。此应用程序仅需要openid验证。
state OAuth协议定义此参数。样本Java Web 应用程序使用此代码来检查是否可以与Oracle Identity Cloud Service建立通信。对于此示例,此参数的值为1234
response_type 授权代码授权类型所需的参数。对于此示例,此参数的值为code

用户登录后,Oracle Identity Cloud Service会将用户的 Web 浏览器重定向到开发人员必须实施的回调 URL。Java Web 应用程序使用CallbackServlet来处理此请求。

public class CallbackServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //After Oracle Identity Cloud Service authenticates the user, the browser is redirected to the
        //callback URL, implemented as a Servlet.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Getting the authorization code from the "code" parameter
        String authzCode = request.getParameter("code");
        //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
        AuthenticationResult ar = am.authorizationCode(authzCode);
        //Getting the Access Token object and its String value.
        AccessToken access_token = ar.getToken(OAuthToken.TokenType.ACCESS_TOKEN);
        String access_token_string = access_token.getToken();
        //Getting the ID Token object and its String value.
        IdToken id_token = ar.getToken(OAuthToken.TokenType.ID_TOKEN);
        String id_token_string = id_token.getToken();
        //Validating both Tokens to acquire information for User such as UserID, 
        //DisplayName, list of groups and AppRoles assigned to the user.
        IdToken id_token_validated = am.validateIdToken(id_token_string);
        //Storing information into the HTTP Session.
        HttpSession session=request.getSession();
        session.setAttribute("access_token", access_token_string);
        session.setAttribute("id_token", id_token_string);
        session.setAttribute("userId", id_token_validated.getUserId());
        session.setAttribute("displayName", id_token_validated.getDisplayName());
	//Forwarding the request to the Home page.
        request.getRequestDispatcher("private/home.jsp").forward(request, response);
    }
}	

应用程序请求授权代码参数并使用它来调用Java SDK 的AuthenticationManager.authorizationCode()方法,以请求访问标记和 id 标记。然后,Servlet 使用AuthenticationManager实例来验证 ID 标记。AuthenticationManager.validateIdToken()方法返回IdToken对象的实例,该对象包含用户信息,例如显示名称、用户 id 以及分配给用户的组和应用程序角色的列表。访问标记和 Id 标记值,一些用户信息都存储在 HTTP 会话对象中,以便可以将请求转发到名为/private/home.jsp的应用程序中受保护的 URL。除了/private/home.jsp之外,Java Web 应用程序还有另一个受保护的URLs:/private/myProfile.jsp

myProfile.jsp页使用以下代码示例获取有关已登录Oracle Identity Cloud Service的用户的详细信息:


<%if(session.getAttribute("access_token")==null) response.sendRedirect("/login.html");%>
<!DOCTYPE html>
<%
/**
 * The /private/myProfile.jsp page accesses the user's access token previously set in the session, 
 * calls the getAuthenticatedUser method to retrieve the user's information, and then formats it as HTML.
 * @author felippe.oliveira@oracle.com
 * @Copyright Oracle
*/
  java.util.Map<String, Object> options = new sampleapp.util.ConnectionOptions().getOptions();
  //Configuration object instance with the parameters loaded.
  oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration configuration = new oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration(options);
  oracle.security.jps.idcsbinding.shared.AuthenticationManager am = oracle.security.jps.idcsbinding.shared.AuthenticationManagerFactory.getInstance(configuration);
  
  //Getting the Access Token and the Id Token from the session object
  String access_token_string = (String)session.getAttribute("access_token");
  String id_token_string = (String)session.getAttribute("id_token");

  //Validating the ID Token to get user information, groups and app roles associated with the user.
  oracle.security.jps.idcsbinding.api.AccessToken access_token_validated = am.validateAccessToken(access_token_string);
  oracle.security.jps.idcsbinding.api.IdToken id_token_validated = am.validateIdToken(id_token_string);
%>

/private/myProfile.jsp页访问在会话中设置的 id 标记值,调用AuthenticationManager.validateIdToken()方法以检索用户信息,然后将其显示为 HTML 内容。


<p><b>Information from the Identity Token:</b></p><p><%
out.println("DisplayName = "+ id_token_validated.getDisplayName() +"<br>");
out.println("IdentityDomain = "+ id_token_validated.getIdentityDomain() +"<br>");
out.println("UserName = "+ id_token_validated.getUserName()+"<br>");
out.println("UserId = "+ id_token_validated.getUserId()+"<br>");
out.println("Issuer = "+ id_token_validated.getIssuer()+"<br>");

java.util.List<oracle.security.jps.idcsbinding.api.IDCSAppRole> appRoles = id_token_validated.getAppRoles();
if(!appRoles.isEmpty()){
   out.println("App Roles:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSAppRole appRole: appRoles){
      out.println("&nbsp;appRole = "+ appRole.getName() +"<br>");
   }//for
}//if

java.util.List<oracle.security.jps.idcsbinding.api.IDCSGroup> groups = id_token_validated.getGroupMembership();
if(!groups.isEmpty()){
   out.println("Groups:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSGroup group: groups){
      out.println("&nbsp;group = "+ group.getName() +"<br>");
   }//for
}//if
%>
</p>
<p><b>Access Token:</b></p><p><%=access_token_string%></p>

要从应用程序和Oracle Identity Cloud Service之间的一次登入中注销用户,Java Web 应用程序将实施LogoutServlet,这将映射/logout URL:

public class LogoutServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session=request.getSession();
        String id_token = (String)session.getAttribute("id_token");
        session.invalidate();
        Map options = new ConnectionOptions().getOptions();
        String logoutURL = (String)options.get(Constants.AUDIENCE_SERVICE_URL) + (String)options.get("logoutSufix") +"?post_logout_redirect_uri=http%3A//localhost%3A8080&id_token_hint="+ id_token;
        response.sendRedirect(logoutURL);
    }
}

此 Servlet 使应用程序的会话无效,然后将用户的 Web 浏览器重定向到Oracle Identity Cloud Service的OAuth注销 URL。