Realm是shiro比較核心的接口,簡單說它的實現類就是校驗用戶輸入的賬號信息的地方.如果想自定義實現一般的配置文件如下:
<!--自定義Realm 繼承自AuthorizingRealm --> <bean id="userRealm" class="xxx.UserRealm">
<!-- 自定義比對器 --> <property name="credentialsMatcher" ref="myCredentialsMatcher"></property> </bean> <!-- 自定義匹配器 繼承自SimpleCredentialsMatcher --> <bean id="myCredentialsMatcher" class="xxx.MyCredentialsMatcher"></bean>
其中類的關鍵代碼:
public class UserRealm extends AuthorizingRealm { public UserRealm() { super(); } @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//這里返回的就是你自定義Token中getPricipal返回的用戶信息對象. Object user = principals.getPrimaryPrincipal(); ...... return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { Object user = authcToken.getPrincipal();
//從數據庫中查找用戶的信息
UserInfo info = Dao.selectUser(user); ...
//按照用戶的輸入的principal信息去數據庫中查詢,然后封裝出比對信息.下面的info.getPwd()代表的就是Credentials信息,一般指的密碼 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, info.getPwd(), getName()); return authenticationInfo; }
//自定義matcher,這里就是對比用戶的輸入的信息封裝成的token和按照用戶輸入的principal(一般就是用戶名)從數據庫中查詢出的信息封裝的info信息,一般就是比對他們的Credentials
public class MyCredentialsMatcher extends SimpleCredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { Object tokenCredentials = getCredentials(token); Object accountCredentials = getCredentials(info); return super.equals(tokenCredentials, accountCredentials); } }
這里紅色的doGetAuthenticationInfo方法是用來按照用戶輸入的principal信息從數據庫中查詢,並將結果作為一個比對信息,比對2者的Credentials信息是否一致,比對時將調用比對器的doCredentialsMatch方法進行比對,所以我們可以在realm中配置自定義的比對器,重寫此方法來達到自定義比對方法,實現特殊的比對邏輯.尤其是token中封裝自定義對象時
.如果一致則登錄成功.而綠色的doGetAuthorizationInfo方法則是作為獲取當前用戶的角色權限相關信息的方法,此方法中要根據用戶信息查詢出相關的角色權限信息並封裝進去.有了此信息之后就可以根據角色和權限信息進行訪問權限的控制了.
一般直接使用usernamePasswordToken即可,但是由於此默認實現一般存儲的為字符串的principal和Credentials信息,如有必要改為存儲自定義對象,則可以自定義token來實現,關鍵代碼:
/* 這里必須說一下,必須要繼承UsernamePasswordToken,因為realm實現中有個suports方法,會判斷token是否被支持,默認的情況下是只支持UsernamePasswordToken的.如需要完全自定義,則需要單獨再realm配置中添加上新的自定義token的類型支持. */ public class MyUserToken extends UsernamePasswordToken { //這個自定義的屬性可以是對象. private Object user; public MyUserToken() { } public MyUserToken(Objectuser) { this.user = user; } @Override public Object getPrincipal() {
//賬號信息 return user; } @Override public Object getCredentials() {
//校驗的信息,其實一般就是指密碼 return user.getPwd(); } }
在用戶登錄時關鍵代碼:
Subject currentUser = SecurityUtils.getSubject(); UserInfo user = new UserInfo(); user.setName("aaa"); user.setPwd("123"); MyUserToken token = new MyUserToken(user); currentUser.login(token); if (currentUser.isAuthenticated()) { //登錄成功 }else{ //失敗 }
總體的思路為使用自定義的token類將用戶輸入的信息封裝,然后采用token進行login操作.此時shiro將使用token中攜帶的用戶信息調用Realm中自定義的doGetAuthenticationInfo方法進行校驗比對.比對成功則登錄成功,並會自動將相關角色權限信息封裝進去.
