單realm實現shiro手機驗證碼登入
阿新 • • 發佈:2019-01-23
上一篇文章寫的是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進行判斷時也要填什麼字元,這裡只是簡單說明,有需要的朋友可以參考一下,根據自己的需求做改動,本人水平有限,不喜勿噴。