摘 要: 本文介绍了Java Servlet中使用Cookie的方法,并结合具体应用给出了对于授权访问通过Cookie进行口令验证的代码。提供了一个通用的软件包,可实现网上各种验证机制。
关键字:Cookie, Java, Servlet,口令验证
Cookies是用户访问Web服务器时由Web服务器写入用户计算机特定目录的一小段信息,它可以被服务器进一步读取加以利用。Java Servlet是运行于Web服务器上的Java代码,它可以接受用户请求,进行相应的处理,并向用户提供反馈。Java Servlet中提供了Cookie类,可以对Cookie进行操作。本文利用这两项技术,实现了纯Java的基于Web的口令验证系统。
一、Java Servlet对Cookie的支持
1. 写入Cookie
Java Servlet中提供了Cookie类,其构造器有两个参数,分别代表Cookie的名字和值。Cookie类中提供了各种方法设置Cookie的属性,如通过setMaxAge( )方法可以设置Cookie的生存时间。若生存时间为负值,代表浏览器关闭Cookie即消失。生存时间为0,代表删除Cookie,生存时间为正数,代表Cookie存在多少秒。
同时Servlet中的HttpServletResponse类提供了addCookie()方法可以将创建好的Cookie写入用户计算机。
如下面的代码可向用户的计算机写入名称为account,值为xyx的Cookie
Cookie c;
HttpServletResponse rp
c=new Cookie("account","xyx");
c.setMaxAge(-1);
rp.addCookie(c);
2. 读取Cookie
Java Servlet中HttpServletRequest类提供了getCookies( )方法可以从相应用户读取Cookie列表,放在Cookie类型的数组中。通过数组中各个Cookie的getName()和getValue()方法可以获取各个Cookie的名称和值。
二、Java Servlet的数据库访问
我们的口令验证系统使用了一个口令数据库验证用户口令。Java Servlet可通过JDBC访问数据库系统。其基本步骤如下:
1.加载程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
2.连接数据源
Connection con = DriverManager.getConnection("jdbc:odbc:数据库名", "", "");
3.创建Statement对象
Statement stmt = con.createStatement ();
4.发送SQL查询语句进行数据库查询
ResultSet rset = stmt.executeQuery (SQL语句);
通过其返回值可以使用getString(x)获取第x列的查询结果。
或发送SQL更新语句修改数据库
stmt.executeUpdate(SQL语句)
在此机制下,我们定义了一个通用的类:pro,在其中定义了checkdb()方法,可以检查dbmame数据库中、tname表的字段名为accountID、值为accountValue的数据项,其PassID字段的值是否为passValue,若是,则返回true,否则返回false.
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class pro{
/* 检查输入的accountValue和passValue和数据库中是否一致
数据库名,表名,账号字段名, 账号值,密码字段名, 密码值 */
boolean checkdb(String dbname, String tname,String accountID, String accountValue,String passID, String passValue){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:"+dbname, "", "");
Statement stmt = con.createStatement ();
/* 查询accountID为accountValue的记录中密码值,
注意其中的但引号和双引号: ' "+accountValue+" ' " */
ResultSet rset = stmt.executeQuery ("select "+passID+" from "+tname+
" where "+accountID+"='"+accountValue+"'");
String dbpass=null;
/* dbpass代表数据库中的符合accountID=accountValue的数据项的密码值 */
while (rset.next ()){
dbpass= rset.getString (1);
}
con.close();
/* 检查数据库中密码值dbpass和参数中的密码值passValue是否一致 */
if (passValue.equals(dbpass))
return (true);
else return(false);
} catch (Exception e) {
return(false);
}
}
}
三、使用Cookie实现登录
在上述pro类中,编写了方法cLogin(),可以实现基于Web的登录。其功能是:执行以后将检查账号和密码是否正确,若正确,则写入Cookie,供以后自动验证用。
代码如下,其变量含义同上。该程序中,首先用checkdb检测账号值accountValue和密码值passValue是否和数据库中匹配,不匹配则登录失败,匹配则向用户机器写入两个Cookie,accountID和passID。分别存放用户的账号值和口令值。
/*第一次登录,如密码正确,将账号和密码写入Cookie,以备以后检测 */
boolean cLogin(HttpServletResponse rp,String dbname, String tname,String accountID,
String accountValue,String passID, String passValue){
/* 检测密码是否正确 */
if( checkdb(dbname, tname,accountID, accountValue,passID, passValue)){
/* 密码正确,写入账号Cookie */
Cookie c=new Cookie(accountID,accountValue);
c.setMaxAge(-1);
rp.addCookie(c);
/* 密码正确,写入密码Cookie */
c=new Cookie(passID,passValue);
c.setMaxAge(-1);
rp.addCookie(c);
return(true);
}
else return(false); /* 密码不正确,返回false */
}
四、使用Cookie随时验证
在pro类中,还编写了方法cCheck(),可以在编程时随时验证用户是否已经正确登录过。如Java Servlet中涉及到访问敏感数据或需要特权的数据时,便可先运行一下cCheck()方法,若返回值为true,才继续执行相关操作。
cCheck()的代码如下,其变量含义同上。该程序中,首先用getCookies( )方法获取用户的Cookie,然后循环比较得到名称为accountID的Cookie中保存的账号值和名称为passID的Cookie中保存的密码值。最后用前面定义过的checkdb( )方法检查Cookie中的账号值accountValue及密码值passValue和数据库中是否一致
/* 获取cookie中的accountID和PassID值, 检测Cookiez中accountID和密码是否正确 */
boolean cCheck(HttpServletRequest rq,String dbname, String tname,String accountID, String passID){
Cookie x[]=rq.getCookies();
String accountValue=null;
String passValue=null;
for(int i=0;i<x.length;i++)
{
String n=x[i].getName(); // 获取Cookie的名称
if(n.equals(accountID))
{ // 获取名称为accountID的Cookie中保存的账号值
accountValue=x[i].getValue();
}
if(n.equals(passID))
{ // 获取名称为passID的Cookie中保存的密码值
passValue=x[i].getValue();
}
}
if( accountValue!=null && passValue!=null)
// 检查Cookie中的accountValue和passValue和数据库中是否一致
return(checkdb(dbname, tname,accountID, accountValue,passID,
passValue));
else return(false);
}
五、注销
由于登录时Cookie的生存期设为负值,因此,用户退出浏览器后,Cookie中保存的账号和密码自动消失,再进行随时验证时将无法通过验证。
为了使用户在退出浏览器之前也可以手工强制退出,pro类中提供了cLogout( )方法来强制删除Cookie。其代码如下,主要是重新写入名称为accountID和passID的Cookie,并将其生存时间设置为0,这样,这些Cookie将立刻删除。以后再用方法cCheck()检测时将找不到这些Cookie,从而无法通过验证。
void cLogout(HttpServletResponse rp,String accountID, String passID){
Cookie c=new Cookie(accountID,"0");
c.setMaxAge(0);
rp.addCookie(c);
c=new Cookie(passID,"0");
c.setMaxAge(0);
rp.addCookie(c);
}
六、修改口令
pro类中提供cChangepass方法修改口令。该方法首先用前面的cCheck()方法检测当前是否已经登录。只有在登录状态才可以修改口令。
程序代码如下。其首先获取名称为accountID的Cookie中保存的账号值,存入变量accountValue。然后在数据库中accountID等于Cookie中保存的账号值的记录中,将passID字段的值设置为新口令newpass,最后将新的口令newpass写入Cookie。
boolean cChangepass(HttpServletResponse rp,HttpServletRequest rq,String dbname,
String tname,String accountID, String passID,String newpass){
if(cCheck(rq,dbname,tname,accountID,passID)){
//已经登录过才可修改口令
try {
String accountValue=null;
Cookie x[]=rq.getCookies();
for(int i=0;i<x.length;i++)
{
String n=x[i].getName();
if(n.equals(accountID))
{ // 获取名称为accountID的Cookie中保存的账号值
accountValue=x[i].getValue();
break;
}
}
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:"+dbname, "", "");
Statement stmt = con.createStatement ();
/* 将满足accountID= accountValue条件的记录中,
passID字段的值设置为新口令newpass
注意其中的但引号和双引号:' "+newpass+" ' where
' "+accountValue+" ' " ;
*/
String sss="update "+tname+" set "+ passID + " = '"+newpass+
"' where "+accountID+ "='"+accountValue+"'";
stmt.executeUpdate(sss);
// 将新的口令newpass写入Cookie
Cookie c=new Cookie(passID,newpass);
c.setMaxAge(-1);
rp.addCookie(c);
con.close();
return(true);
} catch (Exception e) {
return(false); // 发生异常,不可修改口令
}
}
else return(false); // 没有登录过,不可修改口令
}
七、示例程序
为了验证该pro类的使用,定义了一个数据库,在ODBC数据源中添加了一个名称为au1的数据源,数据表名称为pass,包含多个字段,其中账号和口令字段为account1和pass1。
登录的验证程序为:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class c1 extends HttpServlet
{
public void service(HttpServletRequest rq, HttpServletResponse rp)
throws ServletException,IOException
{ pro x=new pro();
rp.setContentType("text/html");
PrintWriter out=rp.getWriter();
if(x.cLogin(rp,"au1","pass1","account1",rq.getParameter("account"),
"password1",rq.getParameter("password")))
out.println("login OK");
else
out.println("error in login");
}
}
另外编写了随时验证的程序c2,只要将c1中的if语句该为:
if(x.cCheck(rq,"au1","pass1","account1","password1"))
out.println("already logged in");
else
out.println("not logged in");
}
注销的验证程序c3,只要将c1中的if语句该为:
x.cLogout(rp,"account1","password1");
out.println("logged out");
修改口令的验证程序c4,只要将c1中的if语句该为:
if(x.cChangepass(rp,rq,"au1","pass1","account1","password1",
rq.getParameter("password")))
out.println("Password changed");
else
out.println("Error in ChangingPassword");
Servlet程序和数据库均安装在202.120.127.202计算机中,编制了如下HTML文档验证了整个操作过程。
<form action=http://202.120.127.202:8080/examples/servlet/c1 method=get>
输入账号:<input type=text name=account> <br>
输入口令:<input type=password name=password> <br>
<input type=submit value= "登录">
</form>
<form action=http://202.120.127.202:8080/examples/servlet/c2 method=get>
<input type=submit value= "检测是否登录">
</form>
<form action=http://202.120.127.202:8080/examples/servlet/c3 method=get>
<input type=submit value= "注销">
</form>
<form action=http://202.120.127.202:8080/examples/servlet/c4
method=get>
新口令:<input type= password name=password> <br>
<input type=submit value= "修改口令">
</form>
在账号和密码正确输入并登录之前,修改口令无法进行,检测登录结果显示未登录。在正确登录后,检测登录结果一直为已登录。如果点击注销,或退出浏览器再重新打开页面,检测登录结果为未登录。检测登录结果为已登录方可修改口令。
|