Shiro(三)介绍Shiro 密码的比对与MD5盐值加密,接下来对 多Realm验证和认证策略进行简单的介绍。
存在这样一种场景,我们可能会把安全数据放到不同的数据库,比方说 mysql里有,oracle里也有,mysql里面的加密算法是MD5,oracle里面的加密算法是SHA1。这个时候我们进行用户认证时,就需要同时访问这两个数据库,就需要多个Realm。如果有多个Realm的话,还需要涉及到认证策略的问题。
目录
一、多Realm验证(方式一)
多重认证,主要的类是ModularRealmAuthenticator,他有两个需要配置的属性,一个是Collection(用于存储Realm),另一个是AuthenticationStrategy(用于存储验证的策略 )。
通过查看源码可以看到 ModularRealmAuthenticator.class 中的 doAuthenticate
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
//一个realm
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
//多个realm
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
从上面doAuthenticate方法中可以看到:
-
如果有一个Realm 使用的是
doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); -
如果有多个Realm 使用的是
doMultiRealmAuthentication(realms, authenticationToken);
所以我们可以配置多个Realm 给到 ModularRealmAuthenticator 这个bean,将ModularRealmAuthenticator 单独配置为一个bean,将这个bean 配置给SecurityManager。
配置流程:
1.添加第二个Realm SecondRealm.java
SecondRealm.java 中的 加密算法 为 SHA1
package com.example.shiro.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;
public class SecondRealm extends AuthenticatingRealm{
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("[SecondRealm] doGetAuthenticationInfo:"+token);
//1.把AuthenticationToken 转换称 UsernamePasswordToken
UsernamePasswordToken upToken =(UsernamePasswordToken) token;
//2.从UsernamePasswordToken中获取用户名
String username=upToken.getUsername();
//3.调用数据库方法,从数据库中查询username对应的用户记录
System.out.println("从数据库中获取username:"+username+"对应的用户信息");
//4.判断用户是否存在,若不存在,则抛出UnknownAccountException异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在!");
}
//5.根据用户信息的情况,决定是否需求抛出其他的AutheticationException异常。如用户锁定等
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定!");
}
//6.根据用户的情况,来构建AuthenticationInfo对像并返回,通常使用的实现类是SimpleAuthenticationInfo
//以下信息是从数据库获取的
//1).principal:认证的实体类信息。可以是username,也可以是数据表对应的用户的体类对象
Object principal=username;
//2).credentials:密码(数据库获取的用户的密码)
Object credentials=null;//"fc1709d0a95a6be30bc5926fdb7f22f4";
if(username.equals("admin")){
credentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06";//由下面的main方法对应不同的盐值得到
}else if(username.equals("user")){
credentials = "073d4c3ae812935f23cb3f2a71943f49e082a718";
}
//3).realmName:当前realm对象的name,调用父类的getName()方法即可
String realmName=getName();
//4).盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);//盐值 要唯一
//SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, realmName);
SimpleAuthen