使用MD5加密的登陆demo
最近接手了之前的一个项目,在看里面登陆模块的时候,遇到了一堆问题。现在记录下来。
这个登陆模块的逻辑是这样的
1 首先在登陆之前,调用后台的UserLoginAction类的getRandomKey方法产生一个随机字符串。
2 在前台获得用户名的登陆密码后,首先是要md5对其加密,之后把加密的结果与之前的随机字符串合并,使用md5再次加密,并把最后的结果作为用户的密码传给后台。
3 后台获得前台的用户名后(用户名全局唯一),先找出这个用户的密码(数据库里的真实密码),先用md5加密,再与第一步产生的随机字符串合并,之后使用md5二次加密
4 比照第三步产生的密码与从前台获得的密码。如果相等,说明登陆成功。
OK,我们看代码
起始页面:
//index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<s:action name="index" namespace="/" executeResult="true" var="rd"/>
<!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>
</body>
</html>
index.jsp里面只有一个action请求。
看看struts.xml的配置情况
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="core" namespace="/" extends="struts-default">
<action name="index" class="userLoginAction" method="getRandomKey">
<result name="success">login.jsp</result>
</action>
<action name="login" class="userLoginAction" method="login">
<result name="success">main.jsp</result>
<result name="input">login.jsp</result>
<result name="error">login.jsp</result>
</action>
</package>
</struts>
我引入了Spirng来管理类。
看看UserLoginAction
注意要加上prototype
/**
* @author dell
*
*/
@Component
@Scope("prototype")
public class UserLoginAction extends BaseAction{
/**
* 接收JSP传来的账号与密码
*/
private Users user;
/**
* 随机字符串作为加密密钥
*/
private String randomString;
/**
* 生成随机字符串作为密钥
*/
public String getRandomKey() {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
int length = 6;
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
// logger.info("randomString: " + sb.toString());
this.randomString = sb.toString();
return SUCCESS;
}
}
我们再看看返回的login.jsp
这个文件引入了MD5.js。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>短波应急接入网管理系统</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3" />
<link rel="shortcut icon" href="logo.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="css/common.css">
<script type="text/javascript" src="easyui/jquery.min.js"></script>
<script type="text/javascript" src="easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="js/md5.js"></script>
</head>
<body onload="document.getElementById('loginName').focus()">
<div id="page">
<div class="t">
<center>
<span class="flderr">
<s:fielderror>
<s:param>error_msg</s:param>
</s:fielderror> </span>
</center>
</div>
<form action="login" id="login" method="post" class="ym_login_form" >
<div class="ymlf_row">
<span>用户编号:</span>
<input type="text" id="loginName" name="user.userName" class="ymlf_name" />
</div>
<div class="ymlf_row">
<span>用户密码:</span>
<input type="password" id="loginPassword" name="user.passWord" class="ymlf_password" />
<input type="hidden" id="randomString" name="randomString" value=<s:property value="randomString"/> />
//为什么要加上randomString?自己想一想
</div>
<div class="ymlf_btn_box">
<img src="data:images/bt1.png" class="sub" onclick="mysubmit()" />
<img src="data:images/bt2.png" class="res" onclick="myreset()" />
</div>
</form>
</div>
</body>
<script type="text/javascript">
function myreset(){
$('#login').form('clear');
}
function mysubmit(){
var frm = document.getElementById("login");
if(check(frm)==true)
frm.submit();
}
function check(frm) {
var lgnName = frm.loginName.value;
var lgnPassword = frm.loginPassword.value;
if(lgnName=='') {
$('.flderr').html("请输入用户名");
frm.loginName.focus();
return false;
}
if(lgnPassword=='') {
$('.flderr').html("请输入密码");
frm.loginPassword.focus();
return false;
}
var randomString = '<s:property value="randomString" />';
lgnPassword = hex_md5(lgnPassword);
lgnPassword = lgnPassword+randomString;
lgnPassword = hex_md5(lgnPassword);
$('#login').form('load',{
'user.passWord':lgnPassword
});
return true;
}
document.onkeypress =
function(event) {
var e = event||window.event;
var ele = e.target||e.srcElement;
var k = e.which||e.keyCode;
if(k == 13 && ele.id == 'loginPassword')
mysubmit();
}
</script>
</html>
提交的结果给了login那个aciton,最后调用的是UserLoginAction的login方法
/**
* 用户登录处理
*
* @return "center_login" or "dept_login" or ERROR
*/
@SuppressWarnings("unchecked")
public String login() {
if (user == null || user.getUserName() == null
|| user.getPassWord() == null) {
return ERROR;
}
// 从客户端传来的加密后的密码
byte[] clientPassword = user.getPassWord().trim().getBytes();
//逻辑就是这样 我自己写的dao就不给大家看了
//根据前台传过来的用户名从数据库取得用户
List<Users> resultList = (List<Users>) utilDAO.findListByProperty("Users", "userName",user.getUserName() ,"");
if (resultList.isEmpty()) { // 该账号不存在
this.addFieldError("error_msg", "该账号不存在");
logger.info("该账号不存在!!");
return ERROR;
} else {
user = resultList.get(0);
// 对用户真实的密码作同样的加密处理
String passwd = (String) user.getPassWord();
System.out.println("passwd 真实的:"+passwd);
MessageDigest md5 = null;
byte[] serverPassword = null;
try {
md5 = MessageDigest.getInstance("MD5");
md5.update(passwd.getBytes());
passwd = new BigInteger(1, md5.digest()).toString(16);
//md5(890617)后的之为09aaa5d27d99ad09a129a0734d52519b
//字符串以0开头,用BigInteger会把开头的0截去,导致位数减少,所以需要判断并补0
if (passwd.length() < 32) {
for (int i = 0; i <32- passwd.length(); i++) {
passwd = '0' + passwd;
}
}
passwd = passwd + this.randomString; //从前台通过s:hidden传来的randomString
System.out.println(randomString+" aaaa"+" "+this);
md5.update(passwd.getBytes());
serverPassword = (new BigInteger(1, md5.digest()).toString(16))
.getBytes();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
if (!MessageDigest.isEqual(clientPassword, serverPassword)) {
this.addFieldError("error_msg", "用户名或密码错误");
logger.info("用户名或密码错误");
return ERROR;
}
this.getSession().put("user", user);
logger.info("登陆成功");
getLevel();
return SUCCESS;
}
}
在改写这个功能的时候,遇到很多问题。对就这么一个小小的登陆,实在是没有想到会碰到那么多问题。
问题1
<s:action name="index" namespace="/" executeResult="true" var="rd"/> 这是让后台产生随机字符串的action调用。
如果把它放在login.jsp里,那么xml的配置文件里是否需要写result?
如果不写result,在前台取不到randomString。这个很容易理解,你只是在login.jsp里调用这个action,login.jsp里凭什么能取到action里面的值呢?
如果写result,按照下面的形式
<action name="index" class="userLoginAction" method="getRandomKey">
<result name="success">login.jsp</result>
</action>
会出现action与jsp调用的死循环。为什么?大家自己想。
我没有办法,最后把让后台产生随机字符串的action调用放到了一个新的index.jsp里面,这个页面的唯一作用就是调用index这个action,返回的结果给login.jsp。
****************************************************
人蠢没办法。
前台直接获取调用action的值方法如下:
前台jsp调用action
//son1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<s:action name="index1" namespace="/" executeResult="false" var="rd"/>
<!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>
<%-- 上面已经指定了acton的变量名为rd 这里直接用就是了 当然前面要加上# --%>
<%-- 另外atr1这个变量在下面的s:debug里是不存在的--%>
<s:property value="#rd.atr1"/>
<s:debug>
</s:debug>
</body>
</html>
struts.xml
<package name="testchain" namespace="/" extends="struts-default">
<action name="index1" class="chain.Action1">
</action>
</package>
public class Action1 extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 4114388780011017030L;
private String atr1;
private String atr2;
public String execute() throws Exception {
System.out.println("set in action1");
atr1="dlf";
return SUCCESS;
}
//省略getset方法
}
问题2
UserLoginAction应该是单例还是多例。
从技术上来说,下面的就是多例
@Component
@Scope("prototype")
public class UserLoginAction extends BaseAction{
去掉 @Scope("prototype")之后就是单例。
如果是单例的话,用户名与密码在高并发下会发生覆盖问题。所以我们得采用多例。任何一个请求都对应唯一的一个action。
那么又出了一个新问题
问题3
请求index这个action,后台产生了随机字符串,我们可以在login.jsp里访问随机字符串,但是
<action name="login" class="userLoginAction" method="login">
<result name="success">main.jsp</result>
<result name="input">login.jsp</result>
<result name="error">login.jsp</result>
</action>
这个action对应的对象是一个全新的对象,它的getRandomKey()方法还没有调用过。它里面的随机字符串还是空值呢。
最后的解决方法是给login.jsp上加上这行代码
<input type="hidden" id="randomString" name="randomString" value=<s:property value="randomString"/> />
它是怎么解决问题的?自己想一想。
使用MD5加密的登陆demo的更多相关文章
- md5加密用户登陆遇到的问题及解决办法
有个项目的登陆模块使用到了cas,应需求要求,用户名和密码传输时使用了md5加密模式,加密的密码可以直接保存在数据库,但是加密的用户名则必须解密出来才行,于是后台的java代码中便写了针对用户名的解密 ...
- Java三行代码搞定MD5加密,测试5c短信网关的demo
看到之前项目中,关于MD5加密的足足写了一个辅助类. 其实在Java中大部分都帮你实现好了,完成MD5加密,主要就三行代码: /** * 对字符串md5加密 * * @param str * @ret ...
- Java 自带MD5加密 Demo
package demo; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; pub ...
- JAVAEE——SSH项目实战05:用户注册、登陆校验拦截器、员工拜访客户功能和MD5加密
作者: kent鹏 转载请注明出处: http://www.cnblogs.com/xieyupeng/p/7170519.html 一.用户注册 显示错误信息到页面上的另一种方法: public ...
- Java和JS MD5加密-附盐值加密demo
JAVA和JS的MD5加密 经过测试:字母和数据好使,中文不好使. 源码如下: ** * 类MD5Util.java的实现描述: * */public class MD5Util { // 获得MD5 ...
- iOS,一行代码进行RSA、DES 、AES、MD5加密、解密
本文为投稿文章,作者:Flying_Einstein(简书) 加密的Demo,欢迎下载 JAVA端的加密解密,读者可以看我同事的这篇文章:http://www.jianshu.com/p/98569e ...
- iOS MD5加密
1.MD5加密 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321 ...
- IOS中把字符串加密/IOS中怎么样MD5加密/IOS中NSString分类的实现
看完过后,你会学到: 1学习IOS开发中的分类实现, 2以及类方法的书写, 3以及字符串的MD5加密/解密. ---------------------------wolfhous---------- ...
- MD5加密相关
demo效果
随机推荐
- SSM实现秒杀系统案例
---------------------------------------------------------------------------------------------[版权申明:本 ...
- OpenResty和Resis一些基本的性能配置
Basics: 1. Ensure that you have not disabled Lua code cache: https://github.com/openresty/lua-nginx- ...
- Dynamics CRM 本地插件注册器连CRMAn unsecured or incorrectly secured fault was received from the other party
今天遇到个问题,在本地打开插件注册器连接到远程CRM服务器时报如下问题 但我在CRM服务器上连接注册器是可以打开的,所以不存在账号权限这类的问题了(当然我用的是超管的账号也不可能存在),最后查询得知是 ...
- springMVC源码分析--AbstractUrlHandlerMapping(三)
上一篇博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMapping了,接下来我们介绍其子类AbstractUrlHand ...
- 【一天一道Leetcode】#190.Reverse Bits
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 我的个人博客已创建,欢迎大家持续关注! 一天一道le ...
- Python pygame安装过程笔记
今天看到一个教程,是关于Python安装pygame模块的.觉得很好,拿来分享一下. 安装Python 额,这个小题貌似在这里很是多余啊.但是为了照顾到刚刚学习Python的童鞋,我还是多啰嗦两句吧. ...
- C链栈实现
#include <stdlib.h> #include <stdio.h> #include"LinkStack.h" const int TRUE = ...
- 【移动开发】startForeground()让服务保持前台级别
最近在使用android 4.1系统的时候,发现在手机休眠一段时间后(1-2小时),后台运行的服务被强行kill掉,有可能是系统回收内存的一种机制,要想避免这种情况可以通过startForegroun ...
- android问题:Installation error: INSTALL_FAILED_CONFLICTING_PROVIDER
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/24196143 Installation error: INSTALL_FAILED_C ...
- 【原创】Nginx+PHP-FPM优化技巧总结
php-fpm的安装很简单,参见PHP(PHP-FPM)手动编译安装.下面主要讨论下如何提高Nginx+Php-fpm的性能. 1.Unix域Socket通信 之前简单介绍过Unix Domain S ...