验证码实现只要输错一次验证码就一直提示验证码错误

大橘子呀 2017-05-12 05:08:16
代码

public class RandomNumUtil {
private ByteArrayInputStream image;//图像
private String str;//验证码
private RandomNumUtil(){
init();//初始化属性
}
/*
* 取得RandomNumUtil实例
*/
public static RandomNumUtil Instance(){
return new RandomNumUtil();
}
/*
* 取得验证码图片
*/
public ByteArrayInputStream getImage(){
return this.image;
}
/*
* 取得图片的验证码
*/
public String getString(){
return this.str;
}
private void init() {
// 在内存中创建图象
int width=80, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图形上下文
Graphics g = image.getGraphics();
// 生成随机类
Random random = new Random();
// 设定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);
// 设定字体
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x,y,x+xl,y+yl);
}
// 取随机产生的认证码(4位数字)
String sRand="";
for (int i=0;i<4;i++){
String rand=String.valueOf(random.nextInt(10));
sRand+=rand;
// 将认证码显示到图象中
g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
// 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
g.drawString(rand,13*i+6,16);
}
//赋值验证码
this.str=sRand;
//图象生效
g.dispose();
ByteArrayInputStream input=null;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try{
ImageOutputStream imageOut = ImageIO.createImageOutputStream(output);
ImageIO.write(image, "JPEG", imageOut);
imageOut.close();
input = new ByteArrayInputStream(output.toByteArray());
}catch(Exception e){
System.out.println("验证码图片产生出现错误:"+e.toString());
}
this.image=input;/* 赋值图像 */
}
/*
* 给定范围获得随机颜色
*/
private Color getRandColor(int fc,int bc){
Random random = new Random();
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);
}
}


public class RandomAction extends ActionSupport{
private ByteArrayInputStream inputStream;
public String execute() throws Exception{
RandomNumUtil rdnu=RandomNumUtil.Instance();
this.setInputStream(rdnu.getImage());//取得带有随机字符串的图片
ActionContext.getContext().getSession().put("random", rdnu.getString());//取得随机字符串放入HttpSession
return SUCCESS;
}
public void setInputStream(ByteArrayInputStream inputStream) {
this.inputStream = inputStream;
}
public ByteArrayInputStream getInputStream() {
return inputStream;
}
}


 * 登录执行的方法
*/

public String login(){

System.out.println("login执行了");
// 调用业务层的类
// 从session中取出RandomAction.java 中生成的验证码random
String arandom = (String) (ActionContext.getContext().getSession()
.get("random"));
String restr="success";
// 下面就是将session中保存验证码字符串与客户输入的验证码字符串对比了
if (arandom.equals(this.getRand())) {
User existUser=userService.login(user);
if(existUser==null){
//登录失败
//this.addActionError("用户名或密码错误");
ActionContext.getContext().put("msg", "用户名或密码错误");
restr="input";
}else{
//登录成功
ActionContext.getContext().getSession().put("username", existUser.getUsername());
ActionContext.getContext().put("msg", "登录成功");
ActionContext.getContext().getSession().put("userid", existUser.getUserid());
ActionContext.getContext().getSession()
.put("existUser",existUser);
restr="success";
}
}else{
this.addActionError("验证码错误");
restr="input";
}
return restr;
}

这个是 UserAction的login方法

只要验证码不输错,其它的输错都没事,但是 只要输错一次验证码无论输入正确的用户名和密码还是错误的用户名和密码,都在登录界面提示验证码错误
...全文
1903 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
可以使用cache去存储对对于ip唯一作为缓存去判断不就更简单
m0_37597430 2017-08-24
  • 打赏
  • 举报
回复
不知道楼主解决这个问题没有,我也遇到了一模一样的问题 我解决的方法是: 因为我用了spring,所以在login的Action中添加一个属性scope="prototype"就可以了。 至于为什么只执行了一次login的action,可能就是因为spring 默认scope 是单例模式,这样只会创建一个Action对象 每次访问都是同一个Action对象,之前的数据也会被保留下来
110成成 2017-05-13
  • 打赏
  • 举报
回复
不执行action?我看js方法没有问题,你在checktosubmit几alert调试下。
大橘子呀 2017-05-12
  • 打赏
  • 举报
回复
引用 8 楼 zc881124 的回复:
[quote=引用 7 楼 nmjuzi 的回复:] [quote=引用 6 楼 zc881124 的回复:] 先验证验证码是否匹配是正确的,如果验证码验证正确,那请在User existUser=userService.login(user); 之后打印existUser,毕竟看不到你的service实现 只要输错一次验证码无论输入正确的用户名和密码还是错误的用户名和密码 你输错之后,后台有没有重新生成验证码,session中的值是否更新了,前端图片有没有重新加载? 其实你都可以在代码中加打印信息,一目了然,比你这在瞎猜猜快很多。
通过后台打印发现 后台的验证码的变化跟前台的验证码变化一致 但是只要输错一次验证码 就不执行login方法了[/quote] 贴出前端form提交。[/quote]

<form class="form-horizontal" id="userlogin" action="user_login" method="post" namespace="/">
	                        <span class="heading">用户登录</span>
	                        <input type="hidden" value="<s:property value='#request.msg'/>" id="msg"></input>
	 						<%-- <s:hidden id="msg" value="%{#session.msg}"></s:hidden> --%>
	                        <div class="form-group">
	                            <input type="text" class="form-control" id="username" name="username" placeholder="用户名" onkeyup="(this.v=function(){this.value=this.value.replace(/[^A-Za-z0-9]+/,'');}).call(this)" onblur="this.v();">
	                            <i class="fa fa-user"></i>
	                        </div>
	                        <div class="form-group help">
	                            <input type="password" class="form-control" id="password" name="password" placeholder="密码">
	                            <i class="fa fa-lock"></i>
	                         
	                        </div>
	                         <div class="form-group">
	                        <s:text name="验证码"></s:text>:<s:textfield name="rand" size="5"></s:textfield><img src="rand.action" onclick="changeValidateCode(this)" title="点击图片刷新验证码"/><s:actionerror /> 
	                       </div>
	                        <s:hidden name="userid"></s:hidden>
	                        <div class="form-group">
	                        	<a href="register.jsp">还没帐号?点我注册</a>
	                            <input type="button" class="btn btn-default" onclick="checktosubmit()" value="登录"/>
	                            
	                        </div>
	                    </form>

<script type="text/javascript">
	function checktosubmit(){  
    var username =document.getElementById("username").value; 
    var password =document.getElementById("password").value;
    var msg=document.getElementById("msg").value;
    if(username=="" || username==null){
    	alert("用户名不能为空");
    	return;
    }else if(password=="" || password==null){
    	alert("密码不能为空");
    	return;
    }else{
	document.getElementById("userlogin").submit();
    }
    }
   window.onload = function() {
   	var m=document.getElementById("msg").value;
   	if(m!=null&&m!=""){
   		alert(m);
   	}
   };
   
 

		function changeValidateCode(obj) {
			//获取当前的时间作为参数,无具体意义 
			var timenow = new Date().getTime();
			//每次请求需要一个不同的参数,否则可能会返回同样的验证码 
			//这和浏览器的缓存机制有关系,也可以把页面设置为不缓存,这样就不用这个参数了。 
			obj.src = "rand.action?d=" + timenow;
		}
	</script>
110成成 2017-05-12
  • 打赏
  • 举报
回复
引用 7 楼 nmjuzi 的回复:
[quote=引用 6 楼 zc881124 的回复:] 先验证验证码是否匹配是正确的,如果验证码验证正确,那请在User existUser=userService.login(user); 之后打印existUser,毕竟看不到你的service实现 只要输错一次验证码无论输入正确的用户名和密码还是错误的用户名和密码 你输错之后,后台有没有重新生成验证码,session中的值是否更新了,前端图片有没有重新加载? 其实你都可以在代码中加打印信息,一目了然,比你这在瞎猜猜快很多。
通过后台打印发现 后台的验证码的变化跟前台的验证码变化一致 但是只要输错一次验证码 就不执行login方法了[/quote] 贴出前端form提交。
大橘子呀 2017-05-12
  • 打赏
  • 举报
回复
引用 6 楼 zc881124 的回复:
先验证验证码是否匹配是正确的,如果验证码验证正确,那请在User existUser=userService.login(user); 之后打印existUser,毕竟看不到你的service实现 只要输错一次验证码无论输入正确的用户名和密码还是错误的用户名和密码 你输错之后,后台有没有重新生成验证码,session中的值是否更新了,前端图片有没有重新加载? 其实你都可以在代码中加打印信息,一目了然,比你这在瞎猜猜快很多。
通过后台打印发现 后台的验证码的变化跟前台的验证码变化一致 但是只要输错一次验证码 就不执行login方法了
110成成 2017-05-12
  • 打赏
  • 举报
回复
先验证验证码是否匹配是正确的,如果验证码验证正确,那请在User existUser=userService.login(user); 之后打印existUser,毕竟看不到你的service实现 只要输错一次验证码无论输入正确的用户名和密码还是错误的用户名和密码 你输错之后,后台有没有重新生成验证码,session中的值是否更新了,前端图片有没有重新加载? 其实你都可以在代码中加打印信息,一目了然,比你这在瞎猜猜快很多。
李德胜1995 2017-05-12
  • 打赏
  • 举报
回复
引用 3 楼 nmjuzi 的回复:
[quote=引用 1 楼 pany1209 的回复:]

可以最先验证验证码
if(验证条件)
		{
			//验证码正确
			if(user!=null)
			{
				ActionContext.getContext().getSession().put("existUser", existUser);
				return "success";
			}
			else{
				//登录失败
				ActionContext.getContext().put("msg", "用户名或者密码错误");
				return "input";
			}
		}
		else{
			//验证码有错误
			ActionContext.getContext().put("msg", "验证码错误");
			return "input";
		}

我是这么写的呢,但是只要错一次,不管对错就会一直错[/quote] 估计是你生成的验证码有问题。。。 用这个试试。。。

<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
Color getRandColor(int fc,int bc){//给定范围获得随机颜色
        Random random = new Random();
        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);
        }
%>
<%
//设置页面不缓存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
  
// 在内存中创建图象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  
// 获取图形上下文
Graphics g = image.getGraphics();
  
//生成随机类
Random random = new Random();
  
// 设定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);
  
//设定字体
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
  
//画边框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);
  
  
// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
    int x = random.nextInt(width);
    int y = random.nextInt(height);
        int xl = random.nextInt(12);
        int yl = random.nextInt(12);
    g.drawLine(x,y,x+xl,y+yl);
}
  
// 取随机产生的认证码(4位数字)
//String rand = request.getParameter("rand");
//rand = rand.substring(0,rand.indexOf("."));
String sRand="";
for (int i=0;i<4;i++){
    String rand=String.valueOf(random.nextInt(10));
    sRand+=rand;
    // 将认证码显示到图象中
    g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));//调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
    g.drawString(rand,13*i+6,16);
}
  
// 将认证码存入SESSION
session.setAttribute("rand",sRand);
  
  
// 图象生效
g.dispose();
  
// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());
out.clear();
out = pageContext.pushBody();
%>
在jsp页面使用<img src="xxx.jsp">引入。。。
大橘子呀 2017-05-12
  • 打赏
  • 举报
回复
引用 2 楼 yanmengdewo 的回复:
服务端保存的验证码不能放在session中,当用户输错,页面验证码刷新但session中的得不到刷新啊 要在业务层也把验证码更新才行
	function changeValidateCode(obj) {
			//获取当前的时间作为参数,无具体意义 
			var timenow = new Date().getTime();
			//每次请求需要一个不同的参数,否则可能会返回同样的验证码 
			obj.src = "rand.action?d=" + timenow;
		}
比如只输错密码,验证码也会变,再输入正确的用户名和密码就能成功进去。这个时候的session里的 验证码为什么变了,不太理解 输错验证码,无论输入正确还是错误的密码都会提示验证码错误,得重启服务器才行
大橘子呀 2017-05-12
  • 打赏
  • 举报
回复
引用 1 楼 pany1209 的回复:

可以最先验证验证码
if(验证条件)
		{
			//验证码正确
			if(user!=null)
			{
				ActionContext.getContext().getSession().put("existUser", existUser);
				return "success";
			}
			else{
				//登录失败
				ActionContext.getContext().put("msg", "用户名或者密码错误");
				return "input";
			}
		}
		else{
			//验证码有错误
			ActionContext.getContext().put("msg", "验证码错误");
			return "input";
		}

我是这么写的呢,但是只要错一次,不管对错就会一直错
yanmengdewo 2017-05-12
  • 打赏
  • 举报
回复
服务端保存的验证码不能放在session中,当用户输错,页面验证码刷新但session中的得不到刷新啊 要在业务层也把验证码更新才行
李德胜1995 2017-05-12
  • 打赏
  • 举报
回复

可以最先验证验证码
if(验证条件)
		{
			//验证码正确
			if(user!=null)
			{
				ActionContext.getContext().getSession().put("existUser", existUser);
				return "success";
			}
			else{
				//登录失败
				ActionContext.getContext().put("msg", "用户名或者密码错误");
				return "input";
			}
		}
		else{
			//验证码有错误
			ActionContext.getContext().put("msg", "验证码错误");
			return "input";
		}

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧