自定义shiro的Realm实现和CredentialsMatcher实现以及Token实现
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方法进行校验比对.比对成功则登录成功,并会自动将相关角色权限信息封装进去.