單realm實現shiro手機驗證碼登錄

上一篇文章寫的是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進行判斷時也要填什麼字符,這裏只是簡單說明,有需要的朋友可以參考一下,根據自己的需求做改動,本人水平有限,不喜勿噴。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章