本系列文章將以Apacke Wicket Example裡的範例來進行說明,Wicket的版本為1.5x。
首先,Auth/Roles套件實作了IAuthorizationStrategy介面;當授權策略(authorization strategy)安裝在安全性設定中(WebApplication#getSecuritySettings),Wicket將會自動檢查所有元件(component)是否具備可以初始化(instaintion)或是呈現畫面(render)的權限。
欲進行身份認證時,本身的web application必須繼承AuthenticatedWebApplication(此類別為抽象類別),同時要override裡面的三個methods:
1.newSession:回傳AuthenticatedWebSession的子類別(自訂的Session物件)。
2.getSignInPageClass:回傳登入頁面類別。
3.getWebSessionClass():回傳AbstractAuthenticatedWebSession的子類別。
為了要讓使用者在驗證過後,我們必須在application類別的init()中註冊授權策略(getSecuritySettings().setAuthorizationStrategy(new IAuthorizationStrategy(){...}),同時要override在IAuthorizationStrategy類別中的methods。
1.isInstantiationAuthorized:取得能否建立某項元件。
2.isActionAuthorized:取得能否執行某項行為。
-- 體驗範例程式 --
以下是SignInApplication.java程式碼:
package com.myapp.wicket; import org.apache.wicket.Component; import org.apache.wicket.RestartResponseAtInterceptPageException; import org.apache.wicket.Session; import org.apache.wicket.authorization.Action; import org.apache.wicket.authorization.IAuthorizationStrategy; import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession; import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; import org.apache.wicket.request.component.IRequestableComponent; /** * * @author Hsiao Shengche * @version */ public class SignInApplication extends AuthenticatedWebApplication { public SignInApplication() { } public Class getHomePage() { return Home.class; } @Override protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() { return SignInSession.class; } @Override public Session newSession(Request request, Response response) { //回傳自訂的Session類別 return new SignInSession(request); } @Override protected Class<? extends WebPage> getSignInPageClass() { //回傳登入頁面 return SignIn.class; } @Override protected void init(){ super.init(); //設定字元集 getMarkupSettings().setDefaultMarkupEncoding("UTF-8"); //註冊授權策略 getSecuritySettings().setAuthorizationStrategy(new IAuthorizationStrategy(){ @Override public <T extends IRequestableComponent> boolean isInstantiationAuthorized(Class<T> type) { //回傳能否建立元件(含頁面) //檢查Home.html是否要驗證才能進入 //isAssignableFrom(type)->指的是傳入的元件是否就是我們要的元件 //意指我們只要檢查Home.html此元件而已(若知道runtime的類別,亦可使用instanceof) if (Home.class.isAssignableFrom(type)){ //檢查是否已登入 if (((SignInSession)Session.get()).isSignedIn()){ //若已登入,則允許執行 return true; } //若沒有登入則要導向登入頁面 //throw new RestartResponseAtInterceptPageException(SignIn.class); //介入目前的equest並導向其他頁面 throw new RestartResponseAtInterceptPageException(SignIn.class); } return true; } @Override public boolean isActionAuthorized(Component cmpnt, Action action) { //回傳是否允許執行某項元件的某個動作,目前先允許所有動作 return true; } }); } }
接下來,我們要提供自訂的session類別,它必須繼承AuthenticatedWebSession,相同的它也是一個抽象類別。自訂session必須要override以下兩個methods:
1.authenticate:在此進行身份驗證,使用username及password。
2.getRoles:當使用者通過身份驗證後會呼叫此method,因此在此method中必須提供相對應的角色(roles)。
以下是SignInSession.java範例程式碼:
package com.myapp.wicket; import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; import org.apache.wicket.authroles.authorization.strategies.role.Roles; import org.apache.wicket.request.Request; /** * * @author Hsiao Shengche */ public class SignInSession extends AuthenticatedWebSession { //簡單的使用者 private String user; public SignInSession(Request request) { super(request); } @Override public boolean authenticate(String username, String password) { //進行身份驗證,預設帳密均為wicket final String WICKET = "wicket"; if (user == null) { // 檢查帳密 if (WICKET.equalsIgnoreCase(username) && WICKET.equalsIgnoreCase(password)) { user = username; } } //如果登入成功,那麼AuthenticationWebSession.isSignIn()就會回傳true return user != null; } public String getUser() { return user; } public void setUser(final String user) { this.user = user; } @Override public Roles getRoles() { //此範例不提供角色 return null; } }
在這個範例中,首頁是Home.html,但它必須先經過身份驗證才能看到,因此系統會將未認證的使用者導向SignIn.html頁面進行輸入帳號、密碼並驗證的動作。
以下是SignIn.html的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://wicket.apache.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>SignIn</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <wicket:extend> <span wicket:id = "feedback"/> <p> <i>Username and password are both "wicket"</i> </p> <form wicket:id = "signInForm"> <table> <tr> <td align = "right">Username:</td> <td> <input wicket:id = "username" type = "text" value = "foo@goo.moo" size = "30"/> </td> </tr> <tr> <td align = "right">Password:</td> <td> <input wicket:id = "password" type = "password" value = "password" size="30"/> </td> </tr> <tr> <td></td> <td> <input type = "submit" value = "登入"/> </td> </tr> </table> </form> </wicket:extend> </body> </html>
SignIn.java程式碼如下:
package com.myapp.wicket; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.PasswordTextField; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.value.ValueMap; /** * * @author Hsiao Shengche */ public final class SignIn extends BasePage { public SignIn() { super(); // Create feedback panel and add to page add(new FeedbackPanel("feedback")); // Add sign-in form to page add(new SignInForm("signInForm")); } public SignIn(PageParameters params) { //TODO: process page parameters } public final class SignInForm extends Form<Void> { private static final String USERNAME = "username"; private static final String PASSWORD = "password"; // El-cheapo model for form private final ValueMap properties = new ValueMap(); /** * Constructor * * @param id id of the form component */ public SignInForm(final String id) { super(id); // Attach textfield components that edit properties map model add(new TextField<String>(USERNAME, new PropertyModel<String>(properties, USERNAME))); add(new PasswordTextField(PASSWORD, new PropertyModel<String>(properties, PASSWORD))); } @Override public final void onSubmit() { //按下送出鍵就進行驗證 SignInSession session = getMySession(); // 呼叫AuthenticatedWebSession.signIn(username,password) // 會自動呼叫WebSession.authenticate(username,password) if (session.signIn(getUsername(), getPassword())) { if (!continueToOriginalDestination()) { //導入首頁->表示已驗證通過 setResponsePage(getApplication().getHomePage()); } } else { // 設定錯誤訊息 String errmsg = getString("loginError", null, "登入失敗"); // Register the error message with the feedback panel error(errmsg); } } private String getPassword() { return properties.getString(PASSWORD); } private String getUsername() { return properties.getString(USERNAME); } private SignInSession getMySession() { return (SignInSession) getSession(); } } }
SignOut.html則是登出頁面,按了它會執行SignOut.java並將Session設為invalide,意即取消此次Session所儲存的資料。
以下是SignOut.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://wicket.apache.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>SignOut</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <wicket:extend> <h2>Goodbye!</h2> <wicket:link><a href="Home.html">首頁</a></wicket:link> </wicket:extend> </body> </html>
以下是SignOut.java程式碼:
package com.myapp.wicket; import org.apache.wicket.request.mapper.parameter.PageParameters; /** * * @author Hsiao Shengche */ public final class SignOut extends BasePage { /* * 若要成功登出則要取消此建構子 public SignOut() { super(); } * */ public SignOut(PageParameters params) { getSession().invalidate(); } }
No comments:
Post a Comment