上一篇文章写的是shiro实现手机验证码登录:http://blog.csdn.net/modjie/article/details/79221774 用了多realm的方式,需要自定义token等多个类,实现过程复杂,并且还存在一个问题:密码错误异常UnknownAccountException和用户不存在异常IncorrectCredentialsException捕获出错了,初步猜测是由于realm的验证源码中没有将异常抛出,导致其他realm的异常覆盖了原来的异常,但还未解决,由于本人水平和时间有限,暂时就不去解决了。同时发现这种方法来实现手机验证码的登录实在是太笨太麻烦了。接下来分享一下单realm实现手机验证码登录。
1、在常规的用户名密码登录时,我们会自定义一个realm,在这个realm中加入以下逻辑判断就可以实现了。代码如下
package com.java.travel.realm;
import javax.annotation.Resource;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.java.travel.entity.ExUser;
import com.java.travel.service.ExUserService;
public class UserNamePasswordRealm extends AuthorizingRealm {
@Resource
ExUserService exUserService;
/**
* 为当限前登录的用户授予角色和权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
/**
* 验证当前登录的用户
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//接收输入的用户名
String nickName = (String) token.getPrincipal();
//查看UsernamePasswordToken可知,getCredentials()方法的返回值是char []类型的,所以不能直接转化成string。
char [] ch = (char[]) token.getCredentials();
//接收输入的密码
String password = new String(ch);
ExUser exUser;
// 如果用户名长度为11位,则假设是电话号码,去数据库查询,如果查询不到则返回null。
//如果昵称长度大于11,则表示输入非法,返回null,
//如果查询到了,则判断接收的密码,如果为验证码则表示验证码登录,否则就是普通登录,则传入正确的密码进行验证
if (nickName.length() == 11) {
exUser = exUserService.selectByTelphoneNum(nickName);
if (exUser != null) {
//这里要注意,如果是验证码登录是不需要密码的,因此在控制器中创建token实例时,第二个参数传任意字符串即可,
//然后在这里判断。为了保险起见,我传的是中文的验证码,因为前台输入密码是不能输入中文的。
if (password.equals("验证码")) {
password="验证码";
}else {
password=exUser.getPASSWORD();
}
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(exUser.getTEL(), password,"xx");
return authcInfo;
}else {
return null;
}
} else if (nickName.length() > 11) {
return null;
} else {
exUser = exUserService.selectByNickName(nickName);
if (exUser != null) {
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(exUser.getNICKNAME(), exUser.getPASSWORD(),
"xx");
return authcInfo;
}
else {
return null;
}
}
}
}
2、注释解释的很清楚,这里就不做说明了,接下来是控制器的代码。用户名密码登录代码如下:
/**
* 登录
* @param nickName
* @param password
* @return
*/
@RequestMapping(value = "login", method = RequestMethod.GET)
@ResponseBody
public int login(String nickName, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(nickName, password);
try {
subject.login(token);
return 1;
} catch (UnknownAccountException ex) {// 用户名没有找到。
return -1;
} catch (IncorrectCredentialsException ex) {// 用户名密码不匹配。
return -2;
} catch (AuthenticationException e) {//其他异常
return -3;
}
}
3、前端ajax登录请求
// 登录ajax请求
function loginAjax() {
var nickName = $(".account").val();
var password = $(".password").val();
if (nickName == "") {
shakeModal("账号不能为空");
} else if (password == "") {
shakeModal("密码不能为空");
} else {
$.ajax({
type : "get",
url : "login",
data : {
nickName : nickName,
password : password
},
dataType : "json",
success : function(data) {
if (data == 1) {
alert("登录成功1");
} else if (data == -1) {
shakeModal("账号不存在");
} else if (data == -2) {
shakeModal("密码错误");
} else {
shakeModal("未知错误,请刷新页面重新登录");
}
}
});
}
}
如果是验证码登录的话,只需要将ajax方法中的password改成“验证码”或其他任意字符就可以了,但是要注意,这里传的是什么字符,在token中对password进行判断时也要填什么字符,这里只是简单说明,有需要的朋友可以参考一下,根据自己的需求做改动,本人水平有限,不喜勿喷。