首先使用NetBeans建立一個新的Apache Wicket專案,並命名為myrp。依據原文所寫,作者將Web Application中負責和Open ID OP進行通訊的相關功能,放在model的套件中,其中分為兩個項目:
- model#RegistrationModel:實作各項需要Open ID OP所提供資料的bean類別。
//model#RegistrationModel.java package model; import java.io.Serializable; import java.util.Date; public class RegistrationModel implements Serializable { //這是自訂的使用者資訊類別 //未來可用在寫入資料庫的部份 private String openId; private String fullName; private String emailAddress; private String zipCode; private Date dateOfBirth; private String favoriteColor; public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getZipCode() { return zipCode; } public void setZipCode(String zipCode) { this.zipCode = zipCode; } public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } public String getFavoriteColor() { return favoriteColor; } public void setFavoriteColor(String favoriteColor) { this.favoriteColor = favoriteColor; } } - model#RegistrationService:將會使用到的openid4java函式庫中的各項方法以一類別來實作,並且提供static的呼叫方式。
//model#RegistrationService.java package model; import java.util.HashMap; import java.util.List; import org.apache.wicket.request.IRequestParameters; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.request.mapper.parameter.PageParameters.NamedPair; import org.joda.time.YearMonthDay; import org.openid4java.consumer.ConsumerManager; import org.openid4java.consumer.InMemoryConsumerAssociationStore; import org.openid4java.consumer.InMemoryNonceVerifier; import org.openid4java.consumer.VerificationResult; import org.openid4java.discovery.DiscoveryException; import org.openid4java.discovery.DiscoveryInformation; import org.openid4java.discovery.Identifier; import org.openid4java.message.AuthRequest; import org.openid4java.message.AuthSuccess; import org.openid4java.message.MessageExtension; import org.openid4java.message.ParameterList; import org.openid4java.message.sreg.SRegMessage; import org.openid4java.message.sreg.SRegRequest; import org.openid4java.message.sreg.SRegResponse; public class RegistrationService { private static ConsumerManager consumerManager; //進行OpenID的相關探索動作 @SuppressWarnings("unchecked") public static DiscoveryInformation performDiscoveryOnUserSuppliedIdentifier(String userSuppliedIdentifier) { DiscoveryInformation ret = null; ConsumerManager consumerManager = getConsumerManager(); try { // Perform discover on the User-Supplied Identifier List<DiscoveryInformation> discoveries = consumerManager.discover(userSuppliedIdentifier); // Pass the discoveries to the associate() method... ret = consumerManager.associate(discoveries); } catch (DiscoveryException e) { String message = "Error occurred during discovery!"; System.out.println(message); throw new RuntimeException(message, e); } return ret; } //建立OP進行驗證所需的AuthRequest物件 public static AuthRequest createOpenIdAuthRequest(DiscoveryInformation discoveryInformation, String returnToUrl) { AuthRequest ret = null; try { // Create the AuthRequest object ret = getConsumerManager().authenticate(discoveryInformation, returnToUrl); // Create the Simple Registration Request SRegRequest sRegRequest = SRegRequest.createFetchRequest(); sRegRequest.addAttribute("email", false); sRegRequest.addAttribute("fullname", false); sRegRequest.addAttribute("dob", false); sRegRequest.addAttribute("postcode", false); ret.addExtension(sRegRequest); } catch (Exception e) { String message = "Exception occurred while building AuthRequest object!"; System.out.println(message); throw new RuntimeException(message, e); } return ret; } //1.3.3的PageParameters具有Map功能 //1.5.3並沒有,所以要自己撰寫轉換程式 public static ParameterList toParameterList(PageParameters p) { HashMap<String, String> h = new HashMap<String, String>(); for (NamedPair pair : p.getAllNamed()) { h.put(pair.getKey(), pair.getValue()); } return new ParameterList(h); } public static ParameterList toParameterList(IRequestParameters rP) { HashMap<String, String> h = new HashMap<String, String>(); for (String name : rP.getParameterNames()) { h.put(name, rP.getParameterValue(name).toString()); } return new ParameterList(h); } //處理OP回傳的資訊 public static RegistrationModel processReturn(DiscoveryInformation discoveryInformation, PageParameters pageParameters, String returnToUrl) { RegistrationModel ret = null; // Verify the Information returned from the OP /// This is required according to the spec ParameterList response = new ParameterList(toParameterList(pageParameters)); try { VerificationResult verificationResult = getConsumerManager().verify(returnToUrl, response, discoveryInformation); Identifier verifiedIdentifier = verificationResult.getVerifiedId(); if (verifiedIdentifier != null) { AuthSuccess authSuccess = (AuthSuccess) verificationResult.getAuthResponse(); if (authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)) { MessageExtension extension = authSuccess.getExtension(SRegMessage.OPENID_NS_SREG); if (extension instanceof SRegResponse) { ret = new RegistrationModel(); ret.setOpenId(verifiedIdentifier.getIdentifier()); SRegResponse sRegResponse = (SRegResponse) extension; String value = sRegResponse.getAttributeValue("dob"); if (value != null) { ret.setDateOfBirth(new YearMonthDay(value).toDateMidnight().toDate()); } value = sRegResponse.getAttributeValue("email"); if (value != null) { ret.setEmailAddress(value); } value = sRegResponse.getAttributeValue("fullname"); if (value != null) { ret.setFullName(value); } value = sRegResponse.getAttributeValue("postcode"); if (value != null) { ret.setZipCode(value); } } } } } catch (Exception e) { String message = "Exception occurred while verifying response!"; System.out.println(message); throw new RuntimeException(message, e); } return ret; } //取得openid4java API中進行一連串驗證動作的物件 private static ConsumerManager getConsumerManager() { if (consumerManager == null) { consumerManager = new ConsumerManager(); consumerManager.setAssociations(new InMemoryConsumerAssociationStore()); consumerManager.setNonceVerifier(new InMemoryNonceVerifier(10000)); } return consumerManager; } //如果OP驗證使者成功,要導向的頁面(導向bookmarkable頁面)。 public static String getReturnToUrl() { return "http://localhost:8080/myrp/wicket/bookmarkable/myopenid.InformationReview?is_return=true"; } }
接下來就是網頁的部份,由Netbeans的Apache Wicket plugin所建立的wicket專案會自動將頁面進行一致化的編排,也就是會有共同的header及footer,因此所有的wicket page均要繼承BasePage此類別。
首先是本專案的Appilcation類別及MyRPSession類別,主要用來定義專案的相關屬性以及相關的資訊如何儲存在Session中。
//Application.java
package myopenid;
import org.apache.wicket.Session;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
public class Application extends WebApplication {
public Application() {
}
public Class getHomePage() {
return HomePage.class;
}
@Override
public void init() {
super.init();
this.getMarkupSettings().setDefaultMarkupEncoding("UTF-8");
}
@Override
public Session newSession(Request request, Response response) {
//傳回自訂的Session物件,才能進行正確轉型的動作
return new MyRPSession(request);
}
}
//MyRPSession.java
package myopenid;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.request.Request;
import org.openid4java.discovery.DiscoveryInformation;
public class MyRPSession extends WebSession {
//open-id DiscoveryInformation
private DiscoveryInformation discoveryInformation;
//是否已將DiscoveryInformation資訊寫入Session中
private boolean discoveryInformationStoredInSession;
//指定存在Session中的key值
public static final String DISCOVERY_INFORMATION = "openid-disc";
public MyRPSession(Request request) {
super(request);
}
//此方法指定DiscoveryInformation不存在Session中
public void setDiscoveryInformation(DiscoveryInformation discoveryInformation) {
setDiscoveryInformation(discoveryInformation, false);
}
//可指定DiscoveryInformation是否儲存在Session中
public void setDiscoveryInformation(DiscoveryInformation discoveryInformation, boolean storeInSession) {
this.discoveryInformation = discoveryInformation;
if (storeInSession) {
//將DiscoveryInformtion存在Session中
setAttribute(DISCOVERY_INFORMATION, discoveryInformation);
discoveryInformationStoredInSession = true;
}
}
public DiscoveryInformation getDiscoveryInformation() {
DiscoveryInformation ret = discoveryInformation;
//如果有設定將DiscoveryInformation存在Session中
//就回傳Session中的DiscoveryInfomation
if (discoveryInformationStoredInSession) {
ret = (DiscoveryInformation) getAttribute(DISCOVERY_INFORMATION);
}
return ret;
}
}
再來則是HomePage.html,首頁的html碼部份,它包含了輸入openid的表單(form)。
<!--HomePage.html-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:wicket="http://git-wip-us.apache.org/repos/asf/wicket/repo?p=wicket.git;a=blob_plain;f=wicket-core/src/main/resources/META-INF/wicket-1.5.xsd;hb=master"
xml:lang="en"
lang="en">
<head>
<!--
Apache Wicket 1.5x以上的xml schema
xmlns:wicket="http://git-wip-us.apache.org/repos/asf/wicket/repo?p=wicket.git;a=blob_plain;f=wicket-core/src/main/resources/META-INF/wicket-1.5.xsd;hb=master"
-->
<wicket:head>
<title>Open ID Relying Party</title>
</wicket:head>
</head>
<body>
<wicket:extend>
<form id="OpenIdRegistrationForm" wicket:id="form">
<h1>請輸入你的OpenID以進入本站台!</h1>
<br />
<table border="0">
<tr>
<td><label>你的Open ID:</label></td>
<td>
<input class="biginput" type="text" wicket:id="openId"/>
<input type="submit" wicket:id="confirmOpenIdButton" value="確認OpenID"/>
</td>
</tr>
</table>
</form>
<br/><br/>
</wicket:extend>
</body>
</html>
接下來則是其相對應的java原始碼,HomePage.java。
//HomePage.java
package myopenid;
import model.RegistrationModel;
import model.RegistrationService;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.pages.RedirectPage;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.message.AuthRequest;
public class HomePage extends BasePage {
private String returnToUrl;
public HomePage() {
this(new PageParameters());
}
public HomePage(PageParameters parameters) {
returnToUrl = RegistrationService.getReturnToUrl();
//returnToUrl = urlFor(InformationReview.class, new PageParameters("is_return=true")).toString();
add(new OpenIdRegistrationForm("form", this, returnToUrl));
//add(new BookmarkablePageLink("mylink",InformationReview.class));
}
public static class OpenIdRegistrationForm extends Form {
public OpenIdRegistrationForm(String id, final HomePage owningPage, String returnToUrl) {
this(id, owningPage, returnToUrl, new RegistrationModel());
}
@SuppressWarnings("serial")
public OpenIdRegistrationForm(String id, final HomePage owningPage, final String returnToUrl, final RegistrationModel formModel) {
super(id);
setModel(new CompoundPropertyModel(formModel));
TextField openId = new RequiredTextField("openId");
openId.setLabel(new Model("你的Open ID"));
add(openId);
Button confirmOpenIdButton = new Button("confirmOpenIdButton") {
@Override
public void onSubmit() {
String userSuppliedIdentifier = formModel.getOpenId();
DiscoveryInformation discoveryInformation = RegistrationService.performDiscoveryOnUserSuppliedIdentifier(userSuppliedIdentifier);
MyRPSession session = (MyRPSession) owningPage.getSession();
session.setDiscoveryInformation(discoveryInformation, true);
AuthRequest authRequest = RegistrationService.createOpenIdAuthRequest(discoveryInformation, returnToUrl);
//在Wicket 1..5版本以上只要呼叫setResponsePage即可進行redirect的動作
setResponsePage(new RedirectPage(authRequest.getDestinationUrl(true)).getPage());
}
};
add(confirmOpenIdButton);
}
}
}
最後則是OpenID OP驗證過後,會將資料傳回returnToUrl中所指定的網頁InformationReview.html,它包含了一個表單,可以讓使用者檢視資料是否正確。
<!--InformationReview.html-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket="http://git-wip-us.apache.org/repos/asf/wicket/repo?p=wicket.git;a=blob_plain;f=wicket-core/src/main/resources/META-INF/wicket-1.5.xsd;hb=master">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>InformationReview</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<wicket:extend>
<form id="OpenIdRegistrationSuccessForm" wicket:id="form">
<h1>Please review your registration info below.</h1>
<br />
<table border="0">
<tr>
<td><label>Your Open ID:</label></td>
<td><input class="biginput" type="text" wicket:id="openId"/></td>
</tr>
<tr>
<td><label>Full Name:</label></td>
<td><input class="biginput" type="text" wicket:id="fullName"/></td>
</tr>
<tr>
<td><label>Email Address:</label></td>
<td><input class="biginput" type="text" wicket:id="emailAddress"/></td>
</tr>
<tr>
<td><label>Zip Code:</label></td>
<td><input class="biginput" type="text" wicket:id="zipCode"/></td>
</tr>
<tr>
<td><label>Date of Birth:</label></td>
<td><input class="biginput" type="text" wicket:id="dateOfBirth"/></td>
</tr>
<tr>
<td> </td>
<td><input class="bigbutton" type="submit" wicket:id="saveButton" value="Save"/></td>
</tr>
</table>
</form>
</wicket:extend>
</body>
</html>
相對應的InformationReview.java,裡面預留了將資料儲存在資料庫中的method。
//InformationReview.java
package myopenid;
import java.util.Date;
import model.RegistrationModel;
import model.RegistrationService;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.openid4java.discovery.DiscoveryInformation;
public final class InformationReview extends BasePage {
public InformationReview() {
this(new PageParameters());
}
public InformationReview(PageParameters pageParameters) {
RegistrationModel registrationModel = new RegistrationModel();
if (!pageParameters.isEmpty()) {
String isReturn = pageParameters.get("is_return").toString();
if (isReturn.equals("true")) {
MyRPSession session = (MyRPSession) getSession();
DiscoveryInformation discoveryInformation = session.getDiscoveryInformation();
registrationModel = RegistrationService.processReturn(discoveryInformation, pageParameters, RegistrationService.getReturnToUrl());
if (registrationModel == null) {
error("Open ID Confirmation Failed. No information was retrieved from the OpenID Provider. You will have to enter all information by hand into the text fields provided.");
}
}
}
add(new OpenIdRegistrationInformationDisplayForm("form", registrationModel));
}
public static class OpenIdRegistrationInformationDisplayForm extends Form {
@SuppressWarnings("serial")
public OpenIdRegistrationInformationDisplayForm(String id, RegistrationModel registrationModel) {
super(id, new CompoundPropertyModel(registrationModel));
TextField openId = new TextField("openId");
openId.setEnabled(false);
add(openId);
TextField fullName = new RequiredTextField("fullName");
add(fullName);
TextField emailAddress = new RequiredTextField("emailAddress");
add(emailAddress);
TextField zipCode = new TextField("zipCode");
add(zipCode);
TextField dateOfBirth = new RequiredTextField("dateOfBirth", Date.class);
add(dateOfBirth);
Button saveButton = new Button("saveButton") {
public void onSubmit() {
if (saveRegistrationInfo()) {
info("Registration Info saved.");
} else {
error("Registration Info could not be saved!");
}
}
};
add(saveButton);
}
private boolean saveRegistrationInfo() {
return true;
}
}
}
No comments:
Post a Comment