Lekce 11 - Wicket - Přihlašování
V minulé lekci, Wicket - JavaScript a CSS, pokračování, jsme přidali editační stránku.
V této lekci upravíme hlavní stránku tak, aby se na ni vytvořené příspěvky zobrazovaly, a také zajistíme, aby příspěvky mohl přidávat pouze administrátor (přihlášený uživatel).
Zobrazení příspěvků na hlavní stránce.
HomePage.java
public HomePage() { // Creates model. IModel<List<Note>> model = new AbstractReadOnlyModel<List<Note>>() { @Override public List<Note> getObject() { NoteDao dao = new NoteDaoImpl(); List<Note> notes = dao.getAllNotes(); return notes; } }; // Creates repeater. ListView<Note> lv = new ListView<Note>("lv", model) { @Override protected void populateItem(ListItem<Note> item) { Note note = item.getModelObject(); Label text = new Label("text", note.getText()); text.setEscapeModelStrings(false); item.add(text); Label date = new Label("date", note.getCreatedDate().toString()); date.add(new AttributeAppender("class", Model.of("date"))); date.setEscapeModelStrings(false); item.add(date); } }; add(lv); }
HomePage.html
<wicket:extend> <div wicket:id="lv" class="message"> <div wicket:id="text"></div> <div wicket:id="date"></div> </div> </wicket:extend>
Nyní nám zbývá zajistit, aby příspěvky mohl přidávat jen autentifikovaný uživatel.
Autentifikace je ověření toho, kdo jste (přihlášení uživatele do aplikace). Autorizace ověřuje, jaká máte práva (může např. prohlížet soubory, ale nemůžete je mazat).
Session
Protokol http je bezestavový. To znamená, že každý požadavek od prohlížeče na webovou stránku je pro něj jedinečný. Neuchovává si žádnou historii. Aby bylo možné spárovat jednotlivé uživatele a jejich požadavky na stránky (a uchovávat historii) existuje několik technik. Jednou z nich je použití cookies, což jsou malé soubory na disku uživatele, které obsahují textové hodnoty ve formě klíč -> hodnota. Při prvním dotazu na stránku od uživatele se na serveru vytvoří sezení (session), což je objekt, který uchovává informace o uživateli na straně serveru. Tento objekt má jedinečné číslo (identifikátor). Kromě požadované stránky se uživateli kromě kódu stránky pošle i soubor cookie, který obsahuje i id, které odpovídá id sezení. S každým dalším požadavkem na server se odesílá i cookie a server z něj zjistí id sezení. Takto je pak schopen rozpoznat jednotlivé uživatele. Do session se ukládá například i jazykové nastavení (locale).
Wicket si ukládá (pomocí serializace) i jednotlivé verze uživatelem navštívených stránek, aby se uživatel mohl vrátit zpět. Identifikátor verze (nazývaný pageId) můžete vidět v adresním řádku prohlížeče.
Pokud používáte prohlížeč Chrome, cookies si zobrazíte následujícím způsobem: Menu -> Settings -> Show advanced settings -> sekce "Privacy", tlačítko "Content settings" -> sekce "Cookies", tlačítko "All cookies and site data …".
Pokud používáte Firefox, postup je následující: Menu -> Options -> záložka "Privacy", odkaz "remove individual cookies".
V našem případě, bude moci příspěvky přidávat kdokoliv, kdo se přihlásí (zaloguje). K přihlášení bude třeba uživatelské jméno a heslo. Vzhledem k tomu, že se jedná o náš osobní web, bude nám stačit jedno uživatelské jméno a heslo, které bude napevno v kódu.
Pro tuto funkcionalitu budeme potřebovat knihovny, které již nejsou součástí balíčku wicket-core. Do pom.xml přidáme další závislost.
<dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-auth-roles</artifactId> <version>${wicket.version}</version> </dependency>
Vlastní session
Nejdříve si vytvoříme vlastní session, která bude umět autentifikaci. Naše session bude dědit od Wicket AuthenticatedWebSession, která má jako předka Session (kterou jsme doposud nevědomky používali, a která uchovávala například verze stránek - viz odstavec s názvem Session). Z AuthenticatedWebSession musíme implementovat dvě metody:
- authenticate()
- getRoles()
Pro nás důležitá je metoda authenticate(). Druhou metody potřebovat nebudeme a necháme ji vracet null.
Metoda authenticate() má dva parametry: username a password a budeme ji používat pro autentifikaci. Vzhledem k tomu, že se jedná o náš blog a příspěvky budeme přidávat pouze my, použijeme ten nejjednodušší způsob.
Je určitě možné vytvořit v databázi tabulku s uživatelskými jmény hesly, ty načítat a porovnávat s údaji zadanými uživatelem. To už nechám na každém z vás.
BasicAuthenticationSession.java
public class BasicAuthenticationSession extends AuthenticatedWebSession { private static final String USERNAME = "admin"; private static final String PASSWORD = "1234"; public BasicAuthenticationSession(Request request) { super(request); } @Override public boolean authenticate(String username, String password) { if (username.equals(USERNAME) && password.equals(PASSWORD)) { return true; } else { return false; } } @Override public Roles getRoles() { return null; } }
Abstraktní třída AuthenticatedWebSession, ze které dědíme, má property boolean signedIn, která v sobě uchovává to, zda je uživatel autentifikován (přihlášen) či ne. Tím, že se uživatel přihlásí (je zavolána naše implementovaná metoda authenticate()) se zároveň nastaví hodnota proměnné signedIn. Pokud chce uživatel zobrazit stránky, které vyžadují autorizaci, zkontroluje se hodnota této proměnné.
Přihlašovací stránka
Naše přihlašovací stránka se bude skládat z formuláře s políčkem (text field) pro zadání uživatelského jména, políčka pro heslo a tlačítka pro odeslání.
LoginPage.java
public class LoginPage extends BasePage { private String username; private String password; public LoginPage() { setDefaultModel(new CompoundPropertyModel(this)); FeedbackPanel feedback = new FeedbackPanel("feedback"); add(feedback); Form loginForm = new Form("loginForm") { @Override protected void onSubmit() { if (AuthenticatedWebSession.get().signIn(username, password)) { continueToOriginalDestination(); } } }; add(loginForm); TextField usernameTF = new TextField("username", new PropertyModel<String>(this, "username")); usernameTF.setRequired(true); loginForm.add(usernameTF); PasswordTextField passwordTF = new PasswordTextField("password", new PropertyModel<String>(this, "password")); loginForm.add(passwordTF); } @Override public void setTitleModelObject() { titleModel.setObject(getString("title.loginPage")); } }
LoginPage.html
<wicket:extend> <h2><wicket:message key="text.login"/></h2> <div wicket:id="feedback"></div> <form wicket:id="loginForm"> <input type="text" wicket:id="username" id="username"/><label for="username"><wicket:message key="form.username"/></label><br/> <input type="password" wicket:id="password" id="password"/><label for="password"><wicket:message key="form.password"/></label><br/> <input type="submit" wicket:message="value:form.submit"/> </form> </wicket:extend>
Pokračování v další lekci, Wicket - Přihlašování, pokračování.