1?引言
??? 通過瀏覽器操作的簡(jiǎn)易性和實(shí)現(xiàn)的方便性,使得基于B/S結(jié)構(gòu)的Web應(yīng)用模式日漸流行;在Web應(yīng)用環(huán)境中,特別是多角色用戶情況下,不同的用戶擁有的操作權(quán)限不同,用戶的身份識(shí)別非常重要。本文對(duì)Web應(yīng)用用戶身份識(shí)別的難點(diǎn)做了簡(jiǎn)單剖析,并從應(yīng)用程序的角度實(shí)現(xiàn)了用戶的身份認(rèn)證。
2?用戶身份識(shí)別的難點(diǎn)——HTTP協(xié)議的無狀態(tài)性
??? HTTP協(xié)議(即超文本傳輸協(xié)議,Hyper Text Transfer Protocol)是一個(gè)應(yīng)用層的網(wǎng)絡(luò)協(xié)議,采用客戶-服務(wù)器模式,用來發(fā)送客戶請(qǐng)求的服務(wù)器上的資源。Web應(yīng)用程序的用戶通過瀏覽器進(jìn)行操作,以瀏覽器作為客戶端采用HTTP協(xié)議同Web服務(wù)器進(jìn)行交互,完成相應(yīng)的工作,由此可見,HTTP協(xié)議是Web應(yīng)用程序的重要基礎(chǔ)之一。
??? 每個(gè)Web站點(diǎn)都有一個(gè)服務(wù)器進(jìn)程,它在特定TCP端口(默認(rèn)80)上不斷監(jiān)聽,以便發(fā)現(xiàn)是否有瀏覽器向它發(fā)出連接建立請(qǐng)求;一旦監(jiān)聽到連接建立請(qǐng)求并建立了TCP連接之后,瀏覽器就向服務(wù)器發(fā)出瀏覽某個(gè)頁面的請(qǐng)求,服務(wù)器接著就返回所請(qǐng)求的頁面作為響應(yīng);發(fā)送完響應(yīng)后,服務(wù)器關(guān)閉TCP連接。服務(wù)器處理下一個(gè)請(qǐng)求與上一個(gè)請(qǐng)求沒有任何關(guān)系,對(duì)于HTTP服務(wù)器而言各個(gè)請(qǐng)求都是一樣的,不會(huì)保留各次處理時(shí)的信息,這就是HTTP協(xié)議的無狀態(tài)性。
??? HTTP的無狀態(tài)性既是優(yōu)點(diǎn),也是缺點(diǎn),協(xié)議原本的設(shè)計(jì)在于共享資源,“無狀態(tài)”的設(shè)計(jì)較有效率也容易實(shí)現(xiàn),很適于它的典型應(yīng)用。但對(duì)基于Web的應(yīng)用,卻很不方便,特別是對(duì)擁有各種角色、權(quán)限的多用戶系統(tǒng)來說,可能要求對(duì)用戶的權(quán)限進(jìn)行區(qū)分,不同部門、不同角色能夠查看的頁面不同,對(duì)同一頁面的操作權(quán)限也可能要做區(qū)分,這就要求對(duì)用戶的身份進(jìn)行驗(yàn)證,通過驗(yàn)證的用戶還要保留其身份標(biāo)識(shí),以維護(hù)對(duì)相關(guān)聯(lián)頁面的操作權(quán)限。因?yàn)镠TTP協(xié)議本身不維護(hù)請(qǐng)求之間的狀態(tài)信息,若僅僅通過協(xié)議本身,服務(wù)器無法判斷各請(qǐng)求之間的關(guān)聯(lián)性,也就是說,我們盡管可以使用戶進(jìn)入Web應(yīng)用的默認(rèn)頁面為登陸頁面,讓用戶輸入用戶登陸名及密碼等信息以實(shí)現(xiàn)用戶身份驗(yàn)證,然后再通過鏈接或其它機(jī)制轉(zhuǎn)到其它相關(guān)頁面,但是如果不采取其它措施,用戶即使不從登陸頁面進(jìn)入也可以通過輸入U(xiǎn)RL的方式對(duì)網(wǎng)站上其它頁面進(jìn)行不受限制的訪問。因而,能夠識(shí)別用戶的身份、識(shí)別一系列遠(yuǎn)程客戶的請(qǐng)求是從同一個(gè)客戶處發(fā)出的,是建立有效的基于Web的應(yīng)用程序的關(guān)鍵。
3?解決之道——善用會(huì)話(Session)對(duì)象
??? 會(huì)話可以認(rèn)為是某個(gè)用戶和服務(wù)器之間的一系列相關(guān)的交互,這個(gè)交互會(huì)持續(xù)一段時(shí)間。對(duì)于單個(gè)用戶而言,會(huì)話過程的開始以用戶開始訪問某個(gè)網(wǎng)站為標(biāo)志,會(huì)話過程的結(jié)束以用戶結(jié)束對(duì)該網(wǎng)站的訪問為標(biāo)志。不同的用戶對(duì)應(yīng)著不同的會(huì)話過程,不同的會(huì)話過程之間互不干涉,互不影響。
??? 按對(duì)象的術(shù)語講,一個(gè)會(huì)話可以看作是一個(gè)對(duì)象,它駐留在服務(wù)器上的應(yīng)用程序中并受應(yīng)用程序的影響。一旦在服務(wù)器上建立了一個(gè)會(huì)話,一個(gè)稱為Session ID 的唯一標(biāo)識(shí)符就與此會(huì)話相關(guān)聯(lián)。每一個(gè)訪問網(wǎng)站的用戶在服務(wù)器端可以擁有自己唯一的一個(gè)會(huì)話對(duì)象,此會(huì)話對(duì)象為此用戶所獨(dú)享,即此會(huì)話對(duì)象同用戶有一一對(duì)應(yīng)的關(guān)系,用戶只能檢索自己的會(huì)話對(duì)象,而不能訪問其它用戶的會(huì)話對(duì)象;并且通過session對(duì)象的設(shè)置屬性的方法(setAttribute)可以將其它對(duì)象綁定到此會(huì)話對(duì)象,相應(yīng)的通過session對(duì)象的取得屬性的方法(getAttribute)可以檢索綁定到此會(huì)話對(duì)象的其它對(duì)象。
??? 注意到會(huì)話是客戶和服務(wù)器之間一一對(duì)應(yīng)的聯(lián)系,這一點(diǎn)非常重要,我們可以通過這個(gè)聯(lián)系將用戶的身份信息綁定到會(huì)話對(duì)象上,解決身份認(rèn)證和權(quán)限區(qū)分問題。
4?簡(jiǎn)單示例
??? 下面,我們借助session對(duì)象,通過采用JSP+JavaBean+數(shù)據(jù)庫的方式實(shí)現(xiàn)一個(gè)用戶認(rèn)證的簡(jiǎn)單示例。
4.1? Web應(yīng)用程序結(jié)構(gòu)
??? Web應(yīng)用的用戶界面結(jié)構(gòu)如下圖所示,用戶首先進(jìn)入登陸頁面 /set/login.htm ,在其中輸入用戶ID和密碼;在 /set/login.jsp中進(jìn)行校驗(yàn),若校驗(yàn)通過,則在session保存用戶身份信息,并根據(jù)用戶所屬部門將頁面導(dǎo)向相應(yīng)部門主頁面,否則,將頁面導(dǎo)向登陸頁面重新輸入用戶ID和密碼;對(duì)于需進(jìn)行身份驗(yàn)證的頁面,從session對(duì)象中檢索用戶身份信息,如果能檢索到,說明用戶已經(jīng)得到身份驗(yàn)證,反之,若檢索不到用戶身份信息,說明用戶還未經(jīng)過身份驗(yàn)證(可能是通過在瀏覽器地址欄輸入U(xiǎn)RL的方式直接進(jìn)入該頁的),則將頁面導(dǎo)向到登陸頁面;若通過認(rèn)證的用戶擁有操作此頁面的權(quán)限,則允許操作,否則,顯示權(quán)限錯(cuò)誤信息。

4.2? JavaBean?
???? 本實(shí)現(xiàn)中,需要用到如下幾個(gè)JavaBean(特殊的類) :
??? User類:即用戶類,表示一個(gè)登陸到網(wǎng)站的用戶,具有用戶編號(hào)、密碼、部門、角色等屬性已及對(duì)這些屬性進(jìn)行存取的相應(yīng)方法。
??? UserManager類:用戶管理員類,對(duì)用戶合法性進(jìn)行校驗(yàn)。實(shí)現(xiàn)代碼如下:
package wxf.set;
import java.sql.*;
public class UserManager{ //用戶管理員類,用來通過查詢數(shù)據(jù)庫對(duì)用戶驗(yàn)證
?????? public User checkUser(String userid,String password){
????????????? /**通過查詢數(shù)據(jù)庫,如果存在用戶編號(hào)為userid并且密碼為password
????????????? ?*的用戶則構(gòu)造一個(gè)User 類的對(duì)象,并對(duì)此User類的對(duì)象設(shè)置userid,
????????????? ?*department,role 等屬性,然后返回此對(duì)象;
????????????? ?*如果不存在編號(hào)為userid并且密碼為password
????????????? ?*的用戶則返回null
??????? */
?????? }
}
4.3? 登陸驗(yàn)證頁面(login.jsp)
<%@ page language="java" %>
<%@ page import="wxf.set.*"%>
<%
? String userid=request.getParameter("userid");
? String password=request.getParameter("password");
? UserManager aUM=new UserManager();
? //校驗(yàn)用戶編號(hào)和密碼,確定是否為合法用戶
User aUser=aUM.checkUser(userid,password);
? if(aUser!=null){ //是合法用戶
? ??? session.setAttribute("user",aUser);? //將aUser對(duì)象綁定到session對(duì)象
? ??? if(aUser.getDepartment().equals("dp1")){
? ?????????? //如果用戶屬于部門1則轉(zhuǎn)到部門1的主界面
? ?????????? response.sendRedirect(response.encodeRedirectUrl("/set/dp1/index.jsp"));
? ??? }
? ??? else if(aUser.getDepartment().equals("dp2")){
? ?????????? //如果用戶屬于部門2則轉(zhuǎn)到部門2的主界面
? ?????????? response.sendRedirect(response.encodeRedirectUrl("/set/dp2/index.jsp"));
? ??? }
? }
??else{
? ??? //不是合法用戶,則轉(zhuǎn)到登陸界面
? ??? response.sendRedirect(response.encodeRedirectUrl("/set/login.htm"));
? }
%>
4.4? 身份驗(yàn)證代碼
??? 非法用戶在未通過身份驗(yàn)證的情況下,可能通過鍵入U(xiǎn)RL非法訪問某個(gè)特定JSP文件,為此,必須對(duì)要保護(hù)的頁面安排身份檢查代碼。因?yàn)閷?duì)每個(gè)登陸到網(wǎng)站的用戶,都可以擁有自己獨(dú)享的唯一的session對(duì)象,每個(gè)用戶只能訪問自己的session對(duì)象;因此,可以在要求認(rèn)證的JSP文件的開頭安排如下代碼:從session對(duì)象中檢索用戶(User)對(duì)象,因?yàn)橛脩羧绻菑牡顷戫撁孢M(jìn)入并且是合法用戶,則在登陸時(shí)已經(jīng)將用戶的身份信息封裝成User對(duì)象綁定到session對(duì)象上了,所以如果能檢索到,說明用戶是經(jīng)過了合法認(rèn)證進(jìn)到該頁面的,否則,說明用戶還未經(jīng)過認(rèn)證,需要將頁面轉(zhuǎn)到認(rèn)證頁面;如果經(jīng)過認(rèn)證,則再從用戶對(duì)象中檢索其角色(role)屬性,若允許此角色的用戶訪問該頁,則顯示頁面內(nèi)容,否則,顯示權(quán)限錯(cuò)誤信息。示例代碼如下:
?????? <%
???? //從session對(duì)象中檢索名稱為user的對(duì)象
? ???User theUser=(User)session.getAttribute("user");?????
???? if(theUser==null){?????? //如果不能能檢索到用戶對(duì)象
? ??? ????response.sendRedirect(response.encodeRedirectUrl("/set/login.htm");
? ???}
??? else{?????? //如果存在用戶對(duì)象則取得用戶的角色信息
? ??? ??String theRole=theUser.getRole();
? ??? ??//假使角色為11的用戶可以訪問
? ??? ??if(!theRole.equals("11")){??
? ?????????? out.println("對(duì)不起,您無權(quán)訪問此頁!");
? ??? ??}
? ??? ??else{
? ?????????? //顯示頁面內(nèi)容????
? ??? ??}
? ??}
%>
5 總結(jié)
??? Web應(yīng)用的關(guān)鍵是要識(shí)別用戶,HTTP協(xié)議的無狀態(tài)性使服務(wù)器無法跟蹤用戶操作的相關(guān)性;JSP內(nèi)建的session對(duì)象,是每個(gè)登陸到網(wǎng)站的用戶獨(dú)自擁有的,我們可以借助session對(duì)象保存用戶的身份信息,對(duì)涉及需要特殊身份才能訪問的頁面設(shè)置身份校驗(yàn)代碼,檢索用戶session對(duì)象中的身份信息進(jìn)行校驗(yàn),可以較好實(shí)現(xiàn)用戶身份識(shí)別。
參考文獻(xiàn)?
【1】謝希仁.計(jì)算機(jī)網(wǎng)絡(luò)(第二版).北京:電子工業(yè)出版社,1999.4
【2】Karl Avedal, Danny Ayers 等.JSP編程指南.北京:電子工業(yè)出版社,2001
【3】黃理,洪亮,等.JSP高級(jí)編程.北京:北京希望電子出版社, 2001
【4】丁振凡.ASP應(yīng)用系統(tǒng)中用戶認(rèn)證設(shè)計(jì).計(jì)算機(jī)時(shí)代,1999(8).
