1. 程式人生 > >單realm實現shiro手機驗證碼登入

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