Witam
Po dłuższej przerwie wracam z tematem który został poruszony na ostatnich szkoleniach. Temat ten nie został rozwiązany, dlatego dzisiaj postaram się dokładnie go opisać.
Podczas tworzenia własnych schematów uwierzytelniania często spotykanym problemem jest brak możliwości przekazywania stosownej informacji użytkownikowi. Często zdarza się, że użytkownik chcący zalogować się do naszej aplikacji nie ma do niej dostępu z innych powodów niż podanie złego hasła lub identyfikatora. Wypadałoby zatem poinformować użytkownika o problemach z jego kontem - blokada, brak płatności itp itd. Niestety podstawowa funkcjonalność ogranicza się do stanu zero-jedynkowego. Na szczęście istnieją metody na zmianę stanu rzeczy poprzez prostą edycję funkcji uwierzytelniania i procesu Login na stronie Logowania.
Tyle tytułem wstępu. Teraz do rzeczy.
Zakładam, że aplikacja posiada własny schemat uwierzytelniania, który pracuje na funkcji custom_auth. Funkcję uwierzytelniającą umieszczono poniżej:
create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
begin
select count(*) into l_count
from users where upper(usr_name) = upper(p_username);
IF l_count > 0 then
select usr_password into l_stored_password
from users where upper(usr_name) = upper(p_username);
if p_password = l_stored_password then
return TRUE;
else
return FALSE;
end if;
ELSE
return FALSE;
END IF;
end;
Funkcja ta sprawdza czy dany użytkownik istnieje w tabeli users a następnie konfrontuje hasło w bazie danych z hasłem podanym podczas logowania. W zależności od tego czy hasło jest zgodne czy tez nie zostaje zwrócona wartość TRUE lub FALSE. Na podstawie tej wartości APEX przedstawi naszemu użytkownikowi informację zawartą w Text Message 'INVALID_CREDENTIALS'. Czyli coś w rodzaju "Nieprawidłowe hasło. Spróbuj ponownie."
Wszystko fajnie ale co jeśli wprowadzimy możliwość blokowania konta. Jeśli użytkownik wpisze 3 razy nieprawidłowe hasło to jego konto zostanie zablokowane. Zmieniamy więc funkcję tak aby przybrała następujący kształt:
create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
blockX number;
begin
select count(*) into l_count
from users where upper(usr_name) = upper(p_username);
IF l_count > 0 then
select usr_password, usr_block into l_stored_password, blockX
from users where upper(usr_name) = upper(p_username);
if blockX <1 then
return FALSE;
end if;
if p_password = l_stored_password then
update users set usr_block=3
where upper(usr_name) = upper(p_username);
return TRUE;
else
update users set usr_block=usr_block-1
where upper(usr_name) = upper(p_username);
return FALSE;
end if;
ELSE
return FALSE;
END IF;
end;
Niby ok, ale użytkownik nie będzie wiedział o zablokowaniu konta. Co zatem należy zrobić aby stosowna informacja ukazała się na ekranie ?
Cała procedura składa się z kilku punktów, które kolejno polegają na dodaniu itemsa aplikacyjnego, zmiany procesu na stronie Login i
1. Dodaj Item aplikacyjny AUTH_MESSAGE. W itemsie tym będzie przetrzymywana informacja dla użytkownika. Ważne aby zastrzec możliwość ustawiania wartości tej zmiennej z przeglądarki. Zaznacz opcję "Restricted" z listy Session State Protection.
2. Na stronie logowania dodaj nowy region typu HTML. Jako template regionu wybierz "No Template" natomiast w źródle wpisz "&AUTH_MESSAGE." Natomiast jako kondycje wyświetlania wybierz "Value of Item in Expression 1 Is NOT NULL" i wpisz w polu Expression1 wartość "AUTH_MESSAGE". Region ten będzie odpowiadał za wyświetlanie informacji użytkownikowi. Kondycja zadba o to aby pokazywał się tylko w momencie gdy jest jakaś informacja do przekazania :)
3. Zmień Proces Login na stronie logowania na następujący:
declare
bresult BOOLEAN := FALSE;
begin
bresult := DBE_CUSTOM_AUTH(:P101_USERNAME,:P101_PASSWORD);
if bresult then
wwv_flow_custom_auth_std.post_login(
P_UNAME => :P101_USERNAME,
P_PASSWORD => :P101_PASSWORD,
P_SESSION_ID => v('APP_SESSION'),
P_FLOW_PAGE => :APP_ID||':'||nvl(:P101_PAGE_ID,'2')
);
else
owa_util.redirect_url('f?p=&APP_ID.:101:&SESSION.');
end if;
end;
W procesie tym na początku sprawdzane jest czy użytkownik podał prawidłowe dane do logowania. Jeśli tak to zostanie uruchomiona standardowa procedura logowania. Jeśli nie to użytkownik zostanie przekierowany na stronę 101 (logowania).
4. Na końcu trzeba tylko zająć się zmienną AUTH_MESSAGE. Wypełnianiem tej wartości zajmie się funkcja uwierzytelniająca.
create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
blockX number;
begin
select count(*) into l_count
from users where upper(usr_name) = upper(p_username);
IF l_count > 0 then
select usr_password, usr_block into l_stored_password, blockX
from users where upper(usr_name) = upper(p_username);
if blockX <1 then
apex_util.set_session_state('LOGIN_MESSAGE','Twoje konto zostało zablokowane.
Skontaktuj się z administratorem !');
return FALSE;
end if;
if p_password = l_stored_password then
update users set usr_block=3
where upper(usr_name) = upper(p_username);
return TRUE;
else
update users set usr_block=usr_block-1
where upper(usr_name) = upper(p_username);
apex_util.set_session_state('LOGIN_MESSAGE','Nieprawidowe Haslo lub id !!!');
return FALSE;
end if;
ELSE
apex_util.set_session_state('LOGIN_MESSAGE','Nieprawidowe Haslo lub id !!!');
return FALSE;
END IF;
end;
W funkcji zastosowano fukncje APEX Api która ustawia wartość podanego Itemsa aplikcaji. W tym przypadku jest to Items AUTH_MESSAGE.
Wystarczy zatem zapisać funkcję aby sprawdzić rezultat.
Na końcu można się pokusić o zmianę wyglądu naszego komunikatu tak aby był identyczny z tym w Template strony. Dla mojego Tematu Graficznego będzie to wyglądało tak:
<div class="t16notification" id="MESSAGE">
<img src="#IMAGE_PREFIX#delete.gif" onclick="$x_Remove('MESSAGE')" style="float:right;" class="pb" alt="" />
&AUTH_MESSAGE.
</div>
Gotowe. Teraz można dodawać inne opcje które pozwolą na poinformowanie uzytkownika o wszystkim co nas trapi i uwiera. Ba! Można pokusić się o personalizację komunikatu :) jak nizej:
19 komentarze: