JavaFX: šifrování H2 databáze, použití frameworku Apache Shiro

Jaromír Vojtaj 25. 2. 2016

Minulý díl by věnován manipulaci s CSV soubory pomocí H2. V dnešním (posledním) článku si ukážeme dvě jednoduché možnosti, jak zabezpečit data pomocí šifrování souborů a přihlašovacích údajů.

První část kapitoly se bude věnovat možnostem zabezpečení dat v H2 databázích. Pro úvod do problematiky vyššího zabezpečení databáze H2 se podíváme na stranu 40–41 v PDF dokumentaci. Tam se dozvíme, že je možné zajistit přístup do databáze pomocí uživatelského jména a hesla. To jsme samozřejmě doposud dělali (i když H2 podporuje i prázdné heslo, což jsme samozřejmě nevyužili). Kromě toho ale nabízí H2 ještě jednu možnost – zašifrovat samotný soubor s databází a zajistit tak uložená data ještě více. Vedou k tomu dvě cesty – jedna v momentě, kdy se vytváří nová databáze a druhá tehdy (náš případ), kdy už je databáze vytvořená, ale při jejím vzniku nebyl soubor zašifrován. Když bychom se vrátili o pár dílů zpátky, kde jsme s H2 databází začínali, tak tam najdeme v administrační konzole hodnotu parametru JDBC URL např. v tomto tvaru:

jdbc:h2:~/test

Přesně toto nastavení (pro administrační aplikaci defaultní) jsme použili při prvním pokusu s H2. Pokud bychom chtěli vytvořit novou databázi se šifrovaným souborem, tak musíme udělat v připojovacím dialogu dvě změny. První z nich bude nová hodnota výše uvedeného parametru:

jdbc:h2:~/test;CIPHER=AES

Tímto novým příkazem jsme jednak nastavili požadavek na šifrování souboru s databází a také jsme určili šifrovací algoritmus. Podle PDF nápovědy na straně 121 je v současné době podporován pouze jeden algoritmus a to sice AES-128. V dřívějších verzích byl k dispozici ještě jeden algoritmus – XTEA – viz např. zde: XTEA.

Druhou změnou bude jiné zadání hesla. Podle vzoru v nápovědě musí mít heslo nový formát:

filepwd userpwd

Vzhledem k tomu, že si přejeme šifrovat i soubor s databází, musíme do nastavení připojovacích parametrů zadat jak heslo pro rozšifrování souboru, tak heslo pro uživatelský přístup k datům. Obě hesla jsou oddělena jednou mezerou. My ale už máme databázi vytvořenou a v ní nějaká data. Bylo by tedy vhodné doplnit šifrování do naší stávající databáze. To je možné dvojím způsobem. První je uveden v dokumentaci na straně 41 a jedná se o terminálový příkaz za pomoci vlastní knihovny H2. My s výhodou využijeme funkčnosti administrační konzole a zkusíme to tam. Obvyklým způsobem ji tedy spustíme a otevřeme menu Nástroje. V něm je položka Změnit šifrování souboru a po jejím otevření uvidíme možnosti tak, jak nám to ukazuje první obrázek v první galerii. Abychom měli jistotu, že si nějak nepochroumáme naší zkušební databázi, tak si vytvoříme novou podle druhého obrázku první galerie. Uživatelské heslo bude nastaveno na hodnotu pokus1.

Můžeme zkusit připojení nově vytvořené databáze, ale není to nutné. Vrátíme se do výše popisovaného menu a nastavíme hodnoty tak, jak to ukazuje třetí obrázek v první galerii. Zde si můžeme všimnout, že se nabízí i nepodporovaný algoritmus šifrování, ale my se nenecháme zmást… Nastavené hodnoty jsou asi jasné z obrázku, takže pouze jednoduchá poznámka: soubor zatím nemáme šifrovaný, takže zadáme heslo pouze do parametru Heslo k šifrování (bude mít hodnotu pokus2). Parametr výše by se použil v případě, že by soubor již byl šifrovaný a my bychom chtěli změnit šifrovací heslo. Spustíme akci a pokud se neobjeví chybové hlášení, proběhlo vše bez problémů. Vrátíme se tedy na stránku s přihlášením a uděláme dvě změny: do parametru JDBC URL přidáme název šifrovacího algoritmu a jako heslo použijeme hodnotu pokus2 pokus1. Kompletní nastavení nám ukazuje čtvrtý obrázek první galerie. Na pátém obrázku v první galerii pak vidíme, že se přihlášení s novými parametry podařilo.

Pokus nanečisto byl tedy úspěšný a my tak můžeme zašifrovat naši zkušební databázi. Postup nebudeme znovu popisovat a odkážeme na šestý obrázek první galerie, kde jsou hodnoty pro nastavení šifrování (heslo je fxguide). Sedmý obrázek v první galerii pak ukazuje změny v připojení k databázi včetně šifrovacího algoritmu a hesla (fxguide fxguide). Na osmém obrázku první galerie je vidět, že se připojení s novým nastavením bez problémů podařilo. Tímto bychom mohli zakončit první kapitolu našeho textu a posunout se k té další. Od začátku dnešního dílu se sice bavíme o zabezpečení dat, ale v jedné věci máme ještě určitou slabinu. Jak při použití PG, tak H2 máme totiž přístupová jména a hesla pro přihlášení k databázi umístěná v aplikaci jako prostý text. Je pravda, že běžný uživatel se do nějak distribuované aplikace těžko dostane, ale možné to samozřejmě je. Dá se tomu částečně zabránit pomocí tzv. obfuskace kódu (zmatek či zmatení). Existují na to různé nástroje a pro zájemce je bližší popis třeba zde: Java Obfuscators.

My se ale touto cestou pouštět nebudeme a zkusíme to jinak. Vycházíme z následující úvahy: když máme v aplikaci uložené přístupové údaje v prostém textu, bylo by možné to nějak změnit? Změnit to samozřejmě lze a my si ukážeme jednu cestu, jak toho dosáhnout. Není určitě jediná a možná ani úplně optimální, ale je určitě funkční a jednoduchá. Při její realizaci vyjdeme z několik předpokladů:

  • hlavní data budou uložená v PG databázi
  • pro uložení přístupových údajů do PG použijeme H2 databázi
  • pro lepší zajištění přístupu budou v H2 uložena přístupová hesla v šifrované podobě
  • pak už není problém nechat přístupové údaje do H2 v aplikaci jako doposud ve formě prostého textu. I kdyby se někdo přes zabezpečení H2 samotné nebo „vykradením“ přístupových údajů v aplikaci dostal do příslušné tabulky, moc si nepomůže

Předpoklady máme jasné a teď co s nimi. Z minulých dílů je zřejmé, že současné připojení k oběma databázím není problém a můžeme tak náš plán klidně realizovat. Zatím ale nemáme vyřešený problém s šifrováním hesel a hlavně pak s následným vyhodnocením správnosti zadání přihlašovacích údajů. Jistě by se to dalo vyřešit i jinak, ale asi málokdo je takovým odborníkem na kryptografii, aby si na to troufl. Zde nám opět pomůže velká rozšířenost Javy a hlavně všech možných nástrojů pro optimální práci s ní. My si zde konkrétně vypomůžeme projektem Apache Shiro – viz Apache Shiro – Java Security Framework (kromě toho existuje ještě několik podobných projektů, jako. např jGuard, Spring Security, JAAS a další). Jak je z odkazu patrné, celý projekt se skládá z několika částí, které zde nebudeme podrobněji popisovat a zaměříme se na tu jedinou, která nás aktuálně zajímá – Autentifikaci. Z této oblasti nakonec použijeme pouhé dva příkazy – pro zašifrování přístupového hesla do PG a porovnání tohoto hesla s heslem, které bude uživatel zadávat. Abychom mohli vše vyzkoušet, musíme si připravit poslední ukázkovou úlohu v naší aplikaci.

V JFXSB si vytvoříme nový FXML soubor a uložíme ho pod názvem samExam8.fxml do adresáře GUI-Files. Jeho celkový vzhled je vidět na prvním obrázku ve druhé galerii. Do schránky si uložíme kostru kontroléru ve verzi Full. Pak otevřeme v IJI naší aplikaci a postupně provedeme následující (již vlastně obvyklé) kroky: vytvoříme novou třídu s příslušným názvem samexam8, vložíme do ní kostru kontroléru, přidáme chybějící závislosti, upravíme deklarace proměnných, do hlavního rozcestníku přidáme volání nové úlohy a připojíme ho do akce příslušného tlačítka. Pak můžeme zkusit aplikaci spustit a úlohu otevřít. Jak to vypadá, nám ukazuje druhý obrázek druhé galerie. Aplikaci máme připravenou a na začátek si ukážeme, jak funguje v Shiro šifrování hesla (obecně libovolného textu) a jak je možné šifrovaný text porovnat s nějakým zadaným. Asi prvním logickým krokem bude stažení příslušné knihovny, což provedeme zde: Shiro latest. Vybereme soubor shiro-all-1.2.4.jar a uložíme ho do aplikačního adresáře libs. To ale ještě není všechno a musíme přidat ještě další dvě knihovny. Z webu SLF4J si stáhneme soubor slf4j-1.7.13.tar.gz a někam ho rozbalíme. Pak si otevřeme nově vytvořený adresář a z jeho kořenové složky zkopírujeme do adresáře libs dva soubory – slf4j-api-1.7.13.jar a slf4j-nop-1.7.13.jar.

Pak už můžeme ve třídě přidat deklaraci příslušné proměnné:

PasswordService passwordService = new DefaultPasswordService();

Pro zašifrování zadaného textu vytvoříme novou proceduru a připojíme ji do akce příslušného tlačítka. Pro manipulaci s hodnotami využijeme připravená editační pole:

private void encPwd() {
        encpwd.setText(passwordService.encryptPassword(plainpws.getText()));
        data.setPrefRowCount(2);
        data.setText("Počet znaků šifrovaného hesla: "+encpwd.getLength()+"\n"+encpwd.getText());}

Výkonný příkaz je pouze ten první, který pomocí jednoduché funkce vezme prostý text z prvního editačního pole a šifrovaný ho uloží do pole druhého. Aby bylo vše přehlednější, dva další příkazy zobrazují v textovém poli počet znaků šifrované verze a její celkový výpis. Výsledek je viditelný na třetím obrázku ve druhé galerii. Pokud se blíže podíváme na formát výsledného řetězce, tak vidíme pouze tři jasné věci:

  • má to „něco“ společného s projektem Shiro
  • pro šifrování byl použit algoritmus SHA-256
  • pro vytvoření šifry bylo použito celkem 500 000 iterací

Ostatní nás už nemusí moc zajímat a naopak můžeme být rádi, jak jednoduše a rychle to za nás jediný příkaz bez jakýchkoliv složitých nastavení a zadávání parametrů zařídil! Uvedená procedura zašifrovala námi zadaný text a my se můžeme pokusit o jeho ověření. Procedura bude opět velmi jednoduchá:

private void matchPwd() {
        Boolean match = passwordService.passwordsMatch(matchpwd.getText(),encpwd.getText());
        matching.setText(match.toString()); }

Opět se jedná o jediný a jednoduchý výkonný příkaz, který porovnává nově zadané heslo s předchozí šifrovanou verzí a logický výsledek zobrazí do příslušného editačního pole. Můžeme samozřejmě zkusit zadat do editačních polí Prosté heslo a Heslo k porovnání různé hodnoty a sledovat výsledek. My si to ale necháme na později a na čtvrtém obrázku druhé galerie ukážeme, že při stejných řetězcích je ověření úspěšné. Máme tedy proceduru pro zašifrování nějakého zadaného textu a umíme zašifrovanou podobu porovnat s prostou. Porovnání probíhá interně tak, že se nově zadaný prostý text zašifruje stejným způsobem, jako v případě vytvoření šifrované podoby a oba šifrované výsledky se porovnají. Pokud máme tohle všechno k dispozici, tak se můžeme pustit do dalších kroků ke kýženému cíli. Kroky to konkrétně budou tři:

  1. znovu si zašifrujeme prostý text a v tomto případě použijeme řetězec safepasswd
  2. do H2 tabulky prihlaseni si přidáme nový záznam, kde jméno uživatele bude safeuser a heslo bude šifrovaný řetězec, který jsme vytvořili v prvním kroku
  3. v PG vytvoříme nového uživatele databáze fxguidedb a zadáme mu stejné parametry, jako má příslušný záznam v H2 tabulce prihlaseni. Uživatele musíme přidat pomocí PG příkazů v terminálu jako správce postgres, protože uživatel fxguide nemá oprávnění k vytvoření nové role či uživatele

Krok číslo 1 je velmi jednoduchý a už ho máme vyzkoušený. Takže k němu pouze upozorníme na pátý a šestý obrázek ve druhé galerii, kde je vidět situace v aplikaci a pak celé zašifrované heslo (pro lepší kopírování je v textovém editoru).

Krok číslo 2 bude také jednoduchý. Stačí nám otevřít si administrátorskou konzolu H2 a vložit do ní jediný příkaz pro přidání několika nových uživatelů. mezi nimi je samozřejmě i náš požadovaný safeuser a s ním také zašifrovaná verze jeho hesla. Sedmý a osmý obrázek druhé galerie ukazují, jak vypadá samotný příkaz pro vložení nových uživatelů a také výsledek dotazu na aktualizovanou příslušnou tabulku.

Krok číslo 3 bude asi nejsložitější. Jak už bylo uvedeno výše, nemůžeme použít aplikaci pgAdmin. Tedy vlastně bychom jí mohli použít, ale v aktuálním stavu zde není připravena možnost pro přihlášení uživatele postgres. Ten má jako jediný oprávnění k tomu, aby mohl přidávat další uživatele. Použijeme proto terminálové příkazy, jak to ukazuje předposlední obrázek ve druhé galerii. Poslední obrázek druhé galerie pak ukazuje příkaz, který by bylo možné využít v případě použití aplikace pgAdmin.

Obě databáze mám tedy připravené a můžeme začít s přidáváním potřebného kódu. Je asi jasné, že jako první musíme přidat funkci pro připojení k databázi H2. Pro navázání spojení s databází tentokrát použijeme trochu pozměněný postup a zapojíme do něj něco, čemu se říká Database Pooling – viz např. zde: What Is Database Pooling. Je víceméně jasné, že pro potřeby naší jednoduché aplikace je to hodně s kanónem na vrabce, ale je to třeba brát jako ukázku možností. Proto také využijeme jednoduchý systém pro tuto činnost, který je implementován přímo v H2 databázi. Je samozřejmě možné využít i jiné nástroje třetích stran, ale pro naše účely by to nemělo už vůbec žádný smysl. Abychom mohli obě varianty porovnat, jako první uvedeme původní kód stejné funkce z předchozího ukázkového příkladu:

private Connection connH2 () {                                  //1
        try { Class.forName("org.h2.Driver");                           //2
        } catch (ClassNotFoundException e) { e.printStackTrace(); }             //3
        try { CONN = DriverManager.getConnection(h2file, jmenoh2, hesloh2); return CONN;    //4
        } catch (SQLException e) { e.getMessage(); return CONN; } }             //5

Pro novou variantu si vytvoříme trochu jinou funkci:

private static JdbcConnectionPool getH2Pool() throws SQLException {             //1
        try { Class.forName("org.h2.Driver");                           //2
        } catch (ClassNotFoundException e) { e.printStackTrace(); }             //3
        JdbcConnectionPool  h2cp = JdbcConnectionPool.create(h2file, jmenoh2, hesloh2);     //4
        return h2cp; }                                      //5

Jak je z obou ukázek patrné, změny jsou docela zásadní. Nová verze funkce má jiný typ, je deklarována jako statická a obsahuje kontrolu výjimek pro chyby v SQL dotazech. Pak následují dva stejné řádky (2 a 3), kde je definován ovladač databáze včetně kontroly chyby. V původní verzi na připojení stačil jediný příkaz, který využíval třídu DriverManager – viz čtvrtý řádek původní funkce. Nová funkce na řádku 4 deklaruje novou proměnnou typu JdbcConnectionPool pomocí stejných parametrů připojení, jako v původním kódu. Druhý příkaz pak definuje na pátém řádku tuto proměnnou jako návratovou hodnotu funkce. Aby mohla funkce řádně fungovat, musíme změnit typ proměnných, které jsou použity jako parametry připojení:

private static final String h2file = "jdbc:h2:file:./Data/fxguidedb;CIPHER=AES";
private static final String jmenoh2 = "fxguide";
private static final String hesloh2 = "fxguide fxguide";

Obdobně i v případě PG použijeme nový přístup. Nová varianta bude od té původní natolik odlišná, že nemá smysl tu starou vůbec uvádět. Funkce je deklarována jako statická, má typ PGPoolingDataSource a kontrolu chyb v SQL příkazech. Na dalších řádcích je také ukázka nastavení parametrů připojení k PG databázi pomocí nově deklarované proměnné. Parametrů je celkem 5, z toho čtyři jsou nám již všeobecně známé. Posledním parametrem je pak maximální počet připojení k databázi. V našem případě je pro ilustraci použita hodnota 100, která je většinou nastavena jako defaultní. Po nastavení parametrů se deklaruje ovladač databáze včetně kontroly chyb. Poslední řádek definuje návratovou hodnotu funkce s veškerým nastavením:

private static PGPoolingDataSource getPgPool (final String jmeno, final String heslo) throws SQLException {
        PGPoolingDataSource source = new PGPoolingDataSource();
        source.setServerName("127.0.0.1:5432");
        source.setDatabaseName("fxguidedb");
        source.setUser(jmeno);
        source.setPassword(heslo);
        source.setMaxConnections(100);
        try { Class.forName("org.postgresql.Driver"); }
        catch (ClassNotFoundException ex) { ex.getMessage(); }
        return source; }

I zde využíváme možnosti, které jsou přímo vestavění v PG aktuální verze. Pokud by měl někdo zájem nebo potřebu, může se poohlédnout po jiných nástrojích, jako je např. PgBouncer nebo PgPool.

Vše už máme skoro připravené ke splnění naší zadané úlohy. K úplné spokojenosti nám chybí z minulých ukázkových úloh zkopírovat procedury dialogMessage a setFocus. Na začátku jsme si poměrně obecně definovali požadavky na zabezpečení přístupu do aplikační databáze. Nyní už jsme pouze krok od naplnění těchto požadavků, takže můžeme docela konkrétně definovat kroky, které to celé implementují:

  1. ve formuláři zadáme uživatelské jméno a heslo do editačních polí Prosté heslo a Šifrované heslo
  2. pomocí přihlašovacích údajů se napojíme na H2 databázi
  3. z příslušné tabulky H2 získáme seznam všech definovaných uživatelů
  4. zjistíme přítomnost námi zadaného uživatele s tomto seznamu
  5. pokud není zadaný uživatel v seznamu, objeví se chybové hlášení a procedura se ukončí. V případě úspěchu se pokračuje dále
  6. pro zadaného uživatele se z H2 tabulky získá šifrovaná verze jeho hesla
  7. šifrovaná verze hesla se porovná s tou zadanou
  8. pokud není heslo zadané správně, objeví se chybové hlášení a procedura se ukončí
  9. pokud je heslo zadáno správně, tak se přihlašovací údaje použijí na připojení k PG a případnému zobrazení dat

Kromě bodů 3 a 4 máme již všechny postupy prakticky vyzkoušené a proto si před konečnou verzí procedury ukážeme, jak oba tyto body naplnit. Za tímto účelem si vytvoříme jednoduchou proceduru a její spuštění přidáme ke tlačítku Zobrazení dat:

private void Users() throws SQLException {                              //1
        JdbcConnectionPool h2pool = getH2Pool();                            //2
        H2CONN = h2pool.getConnection();                                //3
        DSLContext create = DSL.using(H2CONN, SQLDialect.H2);                       //4
        String[] users = create.select().from(PRIHLASENI).fetchArray(PRIHLASENI.UZIVATEL);      //5
        Boolean infield = Arrays.asList(users).contains("safeuser");                    //6
        data.setPrefRowCount(3);                                    //7
        data.setText(Arrays.asList(users).toString()+"\n"+users[1]+"\n"+infield); }         //8
        H2CONN.close();                                         //9
        h2pool.dispose();                                       //10

První řádek je jasný, tam se deklaruje procedura včetně kontroly chyb SQL příkazů. Na druhém řádku je deklarována příslušná proměnná, které je přiřazena hodnota návratové funkce pro H2 pool. Třetí řádek pak využívá tuto proměnnou pro vytvoření připojení k H2 databázi. Toto spojení pak ve čtvrtém řádku využijeme pro přístup ke třídám JOOQ. Na pátém řádku používáme další možnost JOOQ dotazu a do řetězcového pole ukládáme pole všech uživatelských jmen z tabulky prihlaseni. Na šestém řádku využíváme vlastnosti třídy Arrays a zjišťujeme, jestli je v proměnné námi hledané uživatelské jméno. Sedmý řádek nastavuje počet řádků pro zobrazení výsledků ve widgetu TextArea. Osmý řádek pak v tomto widgetu zobrazí seznam uživatelských jmen v tabulce, námi hledané uživatelské jméno a výsledek porovnání. Poslední dva řádky pak uzavírají připojení k databázi a uvolňují toto připojení z H2 poolu. Aby bylo možné novou proceduru vyzkoušet, musíme změnit formát jejího volání a přidat do něj kontrolu chyb:

@FXML void btn_Data_Click(ActionEvent event) throws SQLException { Users(); }

Výsledek našeho snažení je vidět na prvním obrázku ve třetí galerii. Tímto příkladem jsme již připraveni na vytvoření nové procedury, která nám implementuje všech devět výše uvedených kroků. Kód může vypadat např. takto:

private void loginDB() throws SQLException {                                    //1
        JdbcConnectionPool h2pool = getH2Pool();                                //2
        H2CONN = h2pool.getConnection();                                    //3
        DSLContext create = DSL.using(connH2(), SQLDialect.H2);                         //4
        String[] users = create.select().from(PRIHLASENI).fetchArray(PRIHLASENI.UZIVATEL);          //5
        String logName = plainpws.getText();                                    //6
        String logPassw = encpwd.getText();                                 //7
        Boolean inUsers = Arrays.asList(users).contains(logName);                       //8
        setFocus(plainpws);

        if (!inUsers) {                                             //9
            dialogMessage("Zadaný uživatel neexistuje!","Přihlášení uživatele",'E');
            plainpws.setText("");
            encpwd.setText("");
            setFocus(plainpws);
            return; }
        else {                                                  //10
            plainpws.setText("");
            encpwd.setText("");
            setFocus(plainpws);

            String passwd = (String) create                                 //11
                    .select()
                    .from(PRIHLASENI)
                    .where(PRIHLASENI.UZIVATEL.eq(logName))
                    .fetchOne(PRIHLASENI.HESLO);

            Boolean match = passwordService.passwordsMatch(logPassw, passwd);                   //12

            if (!match) {                                           //13
                dialogMessage("Zadané heslo uživatele není správné!", "Přihlášení uživatele", 'E');
                plainpws.setText("");
                encpwd.setText("");
                setFocus(plainpws);
                return; }
            else {                                              //14
                dialogMessage("Uživatel úspěšně přihlášen","Přihlášení uživatele",'I');

                PGPoolingDataSource pgpool = getPgPool("fxguide", "fxguide");                   //15
                PGCONN = pgpool.getConnection();                                //16
                DSLContext pgcreate = DSL.using(PGCONN, SQLDialect.POSTGRES);                       //17

                ObservableList<Record> pgdata = javafx.collections.FXCollections.observableArrayList(pgcreate //18
                        .select()
                        .from(UDAJE)
                        .orderBy(UDAJE.ID)
                        .fetch());

                data.setText(pgdata.toString());                                //19

                create.close();                                         //20
                H2CONN.close();                                         //21
                h2pool.dispose();                                       //22
                pgcreate.close();                                       //23
                PGCONN.close();                                         //24
            } } }

Procedura je sice trochu delší, ale poměrně jednoduchá. Proto si okomentujeme pouze vybrané řádky. Na prvních osmi se definují proměnné pro připojení k H2 databázi, řetězcové pole se všemi uživatelskými jmény z příslušné H2 tabulky, uložení zadaného uživatelského jména a hesla z formuláře a výsledek porovnání obsahu pole uživatelských jmen se jménem zadaným do formuláře. Od devátého řádku ze zjišťuje přítomnost zadaného uživatelského jména v příslušné H2 tabulce. Pokud tam zadané uživatelské jméno není, zobrazí se chybové hlášení a procedura se ukončí. Od desátého řádku se pokračuje v případě, že je zadané uživatelské jméno v pořádku. Na 11. řádku se do proměnné ukládá šifrované heslo zadaného uživatele z příslušné H2 tabulky. Na řádku 12 se porovnává zadané uživatelské heslo z formuláře s jeho šifrovanou verzí v H2 tabulce. Od 13. řádku ze zjišťuje, jestli bylo uživatelské heslo zadáno správně. Pokud to tak není, zobrazí se chybové hlášení a procedura se ukončí. Pokud je heslo zadáno správně, pokračuje se od řádku 14 informačním hlášením. Na řádcích 15 – 17 dojde ke spojení s PG poolem, vytvoří se připojení k PG databázi a JOOQ třídám. Řádek 18 ukládá získaná data z vybrané tabulky PG a řádek 19 tato data zobrazí ve widgetu. Na řádcích 20–24 se pak zavírají všechna otevřená připojení k JOOQ třídám, databázím i H2 poolu.

Proceduru máme tedy připravenou a můžeme jí vyzkoušet. Její volání dáme do akce tlačítka Zobrazení dat. Druhý obrázek třetí galerie ukazuje situaci, kdy je zadán neexistující uživatel. Třetí a čtvrtý obrázek ve třetí galerii pak ukazují situaci, kdy je správně zadaný uživatel, ale jeho heslo správně zadáno není. Poslední tři obrázky třetí galerie (5–7) zobrazují variantu, kdy je vše zadáno správně a připojení k PG databázi je navázáno včetně získání a zobrazení dat. Tímto bychom mohli ukončit dnešní díl, který byl věnován zabezpečení přístupu k datům za pomoci kombinace databází H2 a PG a frameworku Apache Shiro. Jako úplně poslední věc dnešního dílu dáváme do přílohy kompletní kód příslušné procedury: samexam8.java.

Dnešní díl by závěrečným dílem celé série, která se věnovala vybraným ukázkám propojení aplikací v JavaFX s různými databázemi. Byly představeny databáze H2 a PG a různé možnosti propojení databázových dat s aplikací JavaFX, jako je např. JOOQ a Hibernate. Na závěr je potřeba zdůraznit, že seriál neměl být a ani nebyl nějakou učebnicí či tutoriálem. Jeho cílem bylo skutečně pouze ukázat některé možnosti zmíněných programovacích nástrojů a umožnit tak zájemcům nahlédnout do dané problematiky.

Našli jste v článku chybu?
DigiZone.cz: Jetelín končí. Prima ho vyřadila

Jetelín končí. Prima ho vyřadila

Lupa.cz: Elektronika tajemství zbavená. Jak s ní začít?

Elektronika tajemství zbavená. Jak s ní začít?

Podnikatel.cz: OSA zdražuje poplatky. Zaplatíte o polovinu víc

OSA zdražuje poplatky. Zaplatíte o polovinu víc

DigiZone.cz: ČTÚ červenec: rušení trochu vzrostlo

ČTÚ červenec: rušení trochu vzrostlo

DigiZone.cz: Prima a vznik slovenského kanálu

Prima a vznik slovenského kanálu

Lupa.cz: Co vzal čas: internetové kavárny a herny

Co vzal čas: internetové kavárny a herny

Měšec.cz: Udali ho na nelegální software a přišla Policie

Udali ho na nelegální software a přišla Policie

Lupa.cz: Kdo vykrádá LinkedIn? Zjistit to má soud

Kdo vykrádá LinkedIn? Zjistit to má soud

Měšec.cz: Co když na dovolené přijdete o kartu?

Co když na dovolené přijdete o kartu?

Lupa.cz: Samořídicí taxíky jsou tu. Začíná s nimi Uber

Samořídicí taxíky jsou tu. Začíná s nimi Uber

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

120na80.cz: Kam umístit silikony?

Kam umístit silikony?

DigiZone.cz: E! a zákulisí turné Mariah Carey

E! a zákulisí turné Mariah Carey

120na80.cz: Víte, co je svobodná menstruace?

Víte, co je svobodná menstruace?

Podnikatel.cz: Pozor na vykuky, imitují služby České pošty

Pozor na vykuky, imitují služby České pošty

DigiZone.cz: Evropa 2: od září nové vedení

Evropa 2: od září nové vedení

Měšec.cz: Platíme NFC mobilem. Konečně to funguje!

Platíme NFC mobilem. Konečně to funguje!

Podnikatel.cz: Česká pošta vycouvala ze služby ČP Cloud

Česká pošta vycouvala ze služby ČP Cloud

Vitalia.cz: Za její cukrovkou stojí rodiče

Za její cukrovkou stojí rodiče

DigiZone.cz: ČTÚ zveřejnil aktualizovaný D-Book

ČTÚ zveřejnil aktualizovaný D-Book