Servlet+jsp用户登录加上验证码
最近公司有个项目被客户拿去进行漏洞扫描,发现用户登录太简单,容易被暴力破解。当然发现的问题很多,什么反射型XSS,存储型XSS,敏感信息泄露等等。但是我们今天不讲这么多,就说说如何修复暴力破解的问题。由于登录界面未设置图形验证码,也没有对同一用户在连续登录错误时进行限制,导致攻击者可以尝试破解任意已知用户的密码。所以针对这种情况,第一,对同一用户连续登录在规定时间内的次数进行限制,超过则锁定用户。第二,添加图形验证码。
首先给你们看看我的项目结构:


user.sql数据:
SET FOREIGN_KEY_CHECKS=0; -- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE user (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码,加密存储',
`islocked` varchar(10) DEFAULT "0" COMMENT '是否锁定',
`firsttime` varchar(50) DEFAULT NULL COMMENT '第一次登录错误时间',
`count` varchar(10) DEFAULT NULL COMMENT '登录错误次数',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8 COMMENT='用户表'; -- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO user VALUES (null, 'admin', 'e10adc3949ba59abbe56e057f20f883e', '', null, null);
INSERT INTO user VALUES (null, 'nanshan', 'e10adc3949ba59abbe56e057f20f883e', '', null, null);
新建数据库test,导入user.sql即可。
web层:
VerifyCodeServlet.java
package cn.itcast.com.servlet; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import cn.itcast.com.util.VerifyCodeUtils;
/**
*
* @author saule
* @date 2019年6月28日 下午11:39:19
* @Description 验证码servlet
*/
public class VerifyCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int width = 100;
int height = 35;
//获取验证码
String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
//将验证码保存到session
request.getSession().setAttribute("verifyCode", verifyCode);
//向页面输出验证码
VerifyCodeUtils.outputImage(width, height, response.getOutputStream(), verifyCode); } }
LoginServlet.java
package cn.itcast.com.servlet; import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONArray;
import cn.itcast.com.pojo.User;
import cn.itcast.com.service.UserService;
/**
* 正常用户登录流程:
* 1,判断验证码是否正确。
* 2,判断用户是否锁定。
* 3,根据用户名称查找,判断用户是否存在。
* 4,判断密码是否正确。
*/ public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/xml;charset=utf-8");
String username=request.getParameter("username");
String password=request.getParameter("password");
String vercode=request.getParameter("vercode"); String sessionCode=(String) request.getSession().getAttribute("verifyCode");
//清除session中的验证码
request.getSession().removeAttribute("verifyCode"); Map<String,String> map=new HashMap<>();
//验证码错误
if(sessionCode!=null && !sessionCode.equals(vercode.toUpperCase())){
map.put("errcode", "0");
// 转换成json
String json = JSONArray.fromObject(map).toString(); response.getWriter().write(json);
response.getWriter().close();
return;
}
System.out.println(username+":"+password);
UserService userService=new UserService();
User loginUser=new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
Map<String, Object> result = userService.login(loginUser);
if(result.get("errcode").equals("4")){//验证成功
request.getSession().setAttribute("username", username);
request.getSession().setAttribute("password", password);
//用ajax请求用户登录,重定向和转发都是失效的。
//request.getRequestDispatcher("/WEB-INF/success.jsp").forward(request, response);
}
// 转换成json
String json = JSONArray.fromObject(result).toString(); response.getWriter().write(json);
response.getWriter().close(); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response); } }
Service层:
UserService.java
package cn.itcast.com.service; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map; import cn.itcast.com.dao.UserDao;
import cn.itcast.com.pojo.User;
import cn.itcast.com.util.Md5Utils;
/**
*
* @author saule
* @date 2019年6月27日 上午10:50:44
* @Description
*/
public class UserService {
private static final String USER_NOT_EXIST="1";
private static final String USER_IS_LOCK="2";
private static final String PASSWORD_ERROR="3";
private static final String VERIFICATION_SUCCESS="4"; SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //登录操作
public Map<String,Object> login(User loginUser) {
Map<String,Object> loginMap=new HashMap<String, Object>();
UserDao userDao=new UserDao();
User user=userDao.findByName(loginUser.getUsername());
String pwd = Md5Utils.md5(loginUser.getPassword()); if(user==null){//用户不存在
loginMap.put("errcode", USER_NOT_EXIST); }else if(user.getIslocked().equals("1")){//用户被锁定
loginMap.put("errcode", USER_IS_LOCK); }else if(!user.getPassword().equals(pwd)){//密码错误
//超过规定时间,次数不超过4次登录时,将时间与次数重置。
if(user.getFirsttime()!=null){
try {
long firsttime=sdf.parse(user.getFirsttime()).getTime();
long nowtime=new Date().getTime();
if((nowtime-firsttime)>5*60*1000){
user.setFirsttime(null);
user.setCount("0");
userDao.update(user);
}
} catch (ParseException e) {
e.printStackTrace();
}
} if(user.getFirsttime()==null){//初次登录密码错误,记录数据。
user.setFirsttime(sdf.format(new Date()));
user.setCount("1");
userDao.update(user);
}else if(user.getFirsttime()!=null && Integer.valueOf(user.getCount())<3){//连续登陆错误次数小于4次
String newCount = String.valueOf(Integer.valueOf(user.getCount())+1);
user.setCount(newCount);
userDao.update(user); }else{//大于4次且时间间隔小于5分钟则锁定用户。禁止登录。
try {
long firsttime=sdf.parse(user.getFirsttime()).getTime();
long nowtime=new Date().getTime();
if((nowtime-firsttime)<5*60*1000){
user.setFirsttime(null);
user.setCount("0");
user.setIslocked("1");//1表示锁定用户
userDao.update(user);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
loginMap.put("errcode", PASSWORD_ERROR);
loginMap.put("user", user);
}else{
loginMap.put("errcode", VERIFICATION_SUCCESS);
}
return loginMap;
} }
Dao层:
UserDao.java
package cn.itcast.com.dao; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import cn.itcast.com.pojo.User;
import cn.itcast.com.util.JdbcUtils; public class UserDao { //根据用户查询
public User findByName(String username) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
String sql="select * from user where username=?";
try {
conn=JdbcUtils.getConnection();
pst=conn.prepareStatement(sql);
pst.setString(1, username); rs=pst.executeQuery(); if(rs.next()){
User user=new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setIslocked(rs.getString("islocked"));
user.setFirsttime(rs.getString("firsttime"));
user.setCount(rs.getString("count"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
JdbcUtils.close(conn, pst, rs);
} catch (SQLException e) {
e.printStackTrace();
}
} return null;
} //修改用户信息
public void update(User user) {
Connection conn=null;
PreparedStatement pst=null;
String sql="update user set islocked=?,firsttime=?,count=? where id=?"; try {
conn=JdbcUtils.getConnection();
pst = conn.prepareStatement(sql);
pst.setString(1, user.getIslocked());
pst.setString(2, user.getFirsttime());
pst.setString(3, user.getCount());
pst.setInt(4, user.getId());
int row = pst.executeUpdate();
if(row!=0){
System.out.println("修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
JdbcUtils.close(conn, pst, null);
} catch (SQLException e) {
e.printStackTrace();
}
} } }
实体类:
user.java
package cn.itcast.com.pojo;
public class User {
private Integer id;
private String username;
private String password;
private String islocked;//是否锁定,0表示没有锁定;1表示锁定;
private String firsttime;
private String count;//连续登录错误次数
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIslocked() {
return islocked;
}
public void setIslocked(String islocked) {
this.islocked = islocked;
}
public String getFirsttime() {
return firsttime;
}
public void setFirsttime(String firsttime) {
this.firsttime = firsttime;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
}
帮助类:
VerifyCodeUtils.java
package cn.itcast.com.util; import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random; /**
* 验证码生成工具
* @author zl
*/ public class VerifyCodeUtils{ //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static Random random = new Random(); /**
* 使用系统默认字符源生成验证码
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize){
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources){
if(sources == null || sources.length() == 0){
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for(int i = 0; i < verifySize; i++){
verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
}
return verifyCode.toString();
} /**
* 生成随机验证码文件,并返回验证码值
* @param w
* @param h
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, outputFile, verifyCode);
return verifyCode;
} /**
* 输出随机验证码图片流,并返回验证码值
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, os, verifyCode);
return verifyCode;
} /**
* 生成指定验证码图像文件
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
if(outputFile == null){
return;
}
File dir = outputFile.getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
try{
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
outputImage(w, h, fos, code);
fos.close();
} catch(IOException e){
throw e;
}
} /**
* 输出指定验证码图片流
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for(int i = 0; i < colors.length; i++){
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions); g2.setColor(Color.GRAY);// 设置边框色
g2.fillRect(0, 0, w, h); Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, w, h-4); //绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
} // 添加噪点
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++) {
int x = random.nextInt(w);
int y = random.nextInt(h);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
} shear(g2, w, h, c);// 使图片扭曲 g2.setColor(getRandColor(100, 160));
int fontSize = h-4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for(int i = 0; i < verifySize; i++){
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
} g2.dispose();
ImageIO.write(image, "jpg", os);
} private static Color getRandColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
} private static int getRandomIntColor() {
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb) {
color = color << 8;
color = color | c;
}
return color;
} private static int[] getRandomRgb() {
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255);
}
return rgb;
} private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
} private static void shearX(Graphics g, int w1, int h1, Color color) { int period = random.nextInt(2); boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2); for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
} } private static void shearY(Graphics g, int w1, int h1, Color color) { int period = random.nextInt(40) + 10; // 50; boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
} } }
public static void main(String[] args) throws IOException{
File dir = new File("F:/verifies");
int w = 200, h = 80; String verifyCode = generateVerifyCode(4);
File file = new File(dir, verifyCode + ".jpg");
outputImage(w, h, file, verifyCode);
}
}
Md5Utils.java
package cn.itcast.com.util; import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; public class Md5Utils {
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
}
JdbcUtils.java
package cn.itcast.com.util; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle; /**
* @author saule
* @date 2019年6月27日 上午10:23:58
* @Description JDBC帮助类
*/ public class JdbcUtils { private static String driver="com.mysql.jdbc.Driver";
private static String url="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8";
private static String username="root";
private static String password="root"; static {
try {
// 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} public static Connection getConnection() throws SQLException {
//获取连接
Connection con = DriverManager.getConnection(url, username, password); return con;
} //关闭操作
public static void close(Connection con,Statement st,ResultSet rs) throws SQLException{
if(con!=null){
con.close();
}else if(st!=null){
st.close();
}else if(rs!=null){
rs.close();
}
} }
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>youdu</display-name>
<servlet>
<servlet-name>VerifyCodeServlet</servlet-name>
<servlet-class>cn.itcast.com.servlet.VerifyCodeServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.itcast.com.servlet.LoginServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>VerifyCodeServlet</servlet-name>
<url-pattern>/getVerifyCode</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
前端页面:
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录页面</title>
<style type="text/css">
#login{
border: 1px solid deepskyblue;
background-color: blanchedalmond;
width:400px;
height:250px;
padding-left: 100px;
padding-top: 50px;
} </style>
<script type="text/javascript">
//创建一个ajax对象
function getLoginAjax(){
var loginRequest;
if(window.XMLHttpRequest){
loginRequest=new XMLHttpRequest();
}else if(window.ActiveXObject){//window对象中有ActiveXObject属性存在就是IE浏览器的低版本
try{
loginRequest= new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
loginRequest= new ActiveXObject("Microsoft.XMLHTTP");
}
}
return loginRequest;
} //登录方法
function userlogin(){
//获取参数
var username=document.getElementById("username").value;
var password=document.getElementById("password").value;
var vercode=document.getElementById("vercode").value;
/* 此处省略非空校验 */
var loginAjax=getLoginAjax(); loginAjax.open("POST", "login", true);
//请求头
loginAjax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
loginAjax.send("username="+username+"&password="+password+"&vercode="+vercode);
//设置回调函数
loginAjax.onreadystatechange = function() {
//处理响应数据 当信息全部返回,并且是成功
if (loginAjax.readyState == 4 && loginAjax.status == 200) {
//返回的数值类型一般是json格式,比较常见
console.log();
var jsonObj = eval("(" + loginAjax.responseText + ")"); for(var i=0;i<jsonObj.length;i++){
var errcode = jsonObj[i].errcode;
if(errcode==0){
alert("验证码错误");
identifyload();
return false;
}else if(errcode==1){
alert("用户不存在");
identifyload();
return false;
}else if(errcode==2){
alert("用户被锁定,请联系管理。");
return false;
}else if(errcode==3){
var user = jsonObj[i].user;
var locked=user.islocked;
var count=user.count;
if(locked=='0' && count<4){
alert("密码错误,你还有"+(4-count)+"次机会");
identifyload();
}else if(locked=='1'){
alert("用户被锁定,请联系管理。");
}
return false;
}else if(errcode==4){
alert("登录成功");
window.location="http://localhost:8080/youdu/success.jsp";
}
} }
};
} function identifyload() {
document.getElementById("imgcode").src = 'getVerifyCode?nowtime='+ new Date().getTime();
}
</script>
</head>
<body>
<div id="login">
<form action="./login" method="Post" name="login">
<table>
<tr>
<td>用户名:</td>
<td>
<input name="username" type="text" placeholder="请输入昵称" id="username"/><br/><br/>
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input name="password" type="password" placeholder="请输入密码" id="password"/><br/><br/>
</td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input name="vercode" type="text" id="vercode"/>
<img src="./getVerifyCode" height="32" id="imgcode" onclick="identifyload()" title="点击更换验证码">
</td>
</tr>
<tr>
<td height="20"> </td>
</tr> <tr>
<td>
<button type="button" value="登录" onclick="userlogin()">登录</button>
<button type="reset" value="重置">重置</button>
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>登录成功</h3>
用户名:${sessionScope.username}
密码:${sessionScope.password}
</body>
</html>
来个效果图:

最后说几句。虽然用户登录流程简单,但是用servlet和原生js、ajax实现还是有些坑的,特别是现在个个都习惯在框架下写代码,就比如ajax请求后,servlet重定向和转发都会失效,你得想办法登录成功后跳转系统页面。虽然都是比较基础的东西,对于初学者来说还是需要好好掌握。
Servlet+jsp用户登录加上验证码的更多相关文章
- Maven + SSM + Kaptcha 实现用户登录时验证码的获取(问题:302 Found)
pom.xml(对Kaptcha.jar的引用) <!-- 验证码 jar kaptcha--> <dependency> <groupId>com.github. ...
- .NET Core实战项目之CMS 第十六章 用户登录及验证码功能实现
前面为了方便我们只是简单实现了基本业务功能的增删改查,但是登录功能还没有实现,而登录又是系统所必须的,得益于 ASP.NET Core的可扩展性因此我们很容易实现我们的登录功能.今天我将带着大家一起来 ...
- 纯jsp用户登录系统
用纯jsp技术实现用户登录系统,需要用到三个.jsp文件.在文本目录下新建三个.jsp文件,分别命名为login.jsp,logincl.jsp和wel.jsp. 1.login.jsp文件用来放界面 ...
- Servlet——简单用户登录实例+http协议解析
编写项目.用户登录系统1.0版本号 登录界面Servlet: package com.gavin.view; import java.io.IOException; import java.io.Pr ...
- jsp使用servlet实现用户登录 及动态验证码
在进行表单设计中,验证码的增加恰恰可以实现是否为“人为”操作,增加验证码可以防止网站数据库信息的冗杂等... 现在,我将讲述通过servlet实现验证码: 验证码作为一个图片,在页面中为“画”出来的, ...
- jdbc+servlet+jsp实现登录验证
基础知识准备:sql的增删改查. 新增:insert into 表名称(字段名.....)values(字段名....). 修改:update 表名称 set 字段名="新值" ...
- 用servlet实现用户登录案例
以下实现登录窗口 Login.jsp <!--Login.jsp--> <%@ page language="java" import="java.ut ...
- Servlet实现用户登录
1.登录过程分析: 通过表单收集用户的数据,Servlet通过request对象获得用户提交的数据,服务器还需要从数据库中通过sql语句查询有没有表单提交的数据中的用户.有则登录成功,否则,登录失败. ...
- Java EE之servlet实现用户登录
1.在连接数据库的JAVA类中添加查询功能: 在这之前有一个连接数据库的方法: Connection conn=null; PreparedStatement stat=null; ...
随机推荐
- SSM框架的详细解说
文章转载自:http://blog.csdn.net/zhshulin 使用SSM(Spring.SpringMVC和Mybatis)已经有三个多月了,项目在技术上已经没有什么难点了,基于现有的技术就 ...
- selenium中的setUp,tearDown与setUpClass,tearDownClass的区别
def setUpClass(cls): cls.driver = webdriver.Chrome() cls.driver.maximize_window() def setUp(self): s ...
- Sublime Text 3 使用手册
Ctrl+Shift+P:打开命令面板 Ctrl+P:搜索项目中的文件 Ctrl+G:跳转到第几行 Ctrl+W:关闭当前打开文件 Ctrl+Shift+W:关闭所有打开文件 Ctrl+Shift+V ...
- 使用sc 命令写脚本 添加和删除服务 简单应用
添加服务 @echo.服务启动...... @echo off @sc create 服务名 binPath= "%~dp0\服务路径" @sc config 服务名 start= ...
- 小白学Python(8)——pyecharts 入门
简介: pyecharts 是一个用于生成 Echarts 图表的类库. echarts 是百度开源的一个数据可视化 JS 库,主要用于数据可视化.pyecharts 是一个用于生成 Echarts ...
- 纯数据结构Java实现(3/11)(链表)
题外话: 篇幅停了一下,特意去看看其他人写的类似的内容:然后发现类似博主喜欢画图,喜欢讲解原理. (于是我就在想了,理解数据结构的确需要画图,但我的文章写给懂得人看,只配少量图即可,省事儿) 下面正题 ...
- 结合suctf-upload labs-RougeMysql再学习
这篇主要记录一下这道题目的预期解法 做这道题首先要在自己的vps搭建一个rouge mysql,里面要填写需要读取客户端的文件名,即我们上传的phar文件路径 先搭一个rouge mysql测试看看: ...
- mongo常用语法
首先要能进入控制台,进不去自己解决. 基本操作: show users:显示用户 show dbs:显示数据库列表 use <db name> 切换/创建数据库 show collecti ...
- day0203
day02 1.for i in range() --->用于设置for循环的迭代设置. ranage 也是一个前闭后开的. 2.random.randrange() --->随机产生给予 ...
- 礼盒抖动动画(CocosCreator)
推荐阅读: 我的CSDN 我的博客园 QQ群:704621321 这个月还有一天了,别问我为什么是一天,996,懂吗?项目是做不完了,策划又加新功能,又不能安静的改bug了.又是动画 ...