自定义realm实现数据认证
在开发中,有时会与一些nosql或者其他地方保存的数据进行认证,这时候,shiro定义的那些realm类可能不能满足实际的功能需求,这时候我们可以通过自定义一个realm来沟通这些数据。实现认证和权限控制。
首先自定义一个realm,继承自AuthorizingRealm抽象类,并实现它的两个功能:
package com.yinhai.realm;
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;
/**
* 自定义Realm
*/
public class CoustomRealm extends AuthorizingRealm {
//做授权管理的
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//做认证的
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//拿到account
String principal = (String) token.getPrincipal();
if("zhangsan".equals(principal)){ //模拟在数据库中查找用户名的过程,如果找到有,则将用户名和密码返回,没有直接返回null
//通过用户名在数据库中拿到正确的密码,我这里直接省略
String password = "123456";
//新建一个返回信息返回给manager,manager会根据正确的账户和密码自动匹配用户传递过来的账户和密码,参数3是当前realm的名称,底 层会自动生成的。
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, password, this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
然后就可以使用这个realm了:
package com.yinhai;
import com.yinhai.realm.CoustomRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
/**
* 使用自定义realm进行认证测试
*/
public class CostumeRealmAuthTest {
public static void main(String[] args) {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(new CoustomRealm());
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken zhangsan = new UsernamePasswordToken("zhangsan", "123456");
try{
subject.login(zhangsan);
System.out.println(subject.isAuthenticated());
}catch (Exception e){
e.getMessage();
}
}
}
以上是普通的,明文密码匹配方式认证,如果要使用加密的话可以采用以下:
package com.yinhai.realm;
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 org.apache.shiro.util.ByteSource;
public class CostumeMD5Realm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//拿到account
String principal = (String) token.getPrincipal();
if("zhangsan".equals(principal)){ //模拟在数据库中查找用户名的过程,如果找到有,则将用户名和密码返回,没有直接返回null
//通过用户名在数据库中拿到正确的密码,我这里直接省略
String password = "458e4c8450daf785d77e92c6d391e6a2";
//新建一个返回信息返回给manager,manager会根据正确的账户和密码自动匹配用户传递过来的账户和密码,
// 参数3是盐加密规则
// 参数4是当前realm的名称,底层会自动生成的。
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,
password,
ByteSource.Util.bytes("07?*xx"),
this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
使用:
package com.yinhai;
import com.yinhai.realm.CostumeMD5Realm;
import com.yinhai.realm.CoustomRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
public class CostumeMD5RealmAuthTest {
public static void main(String[] args) {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
CostumeMD5Realm costumeMD5Realm = new CostumeMD5Realm();
//获取密码匹配器
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//设置加密方式
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
//设置hash散列次数
hashedCredentialsMatcher.setHashIterations(512);
//设置自定义realm的密码匹配器
costumeMD5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
securityManager.setRealm(costumeMD5Realm);
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken zhangsan = new UsernamePasswordToken("zhangsan", "123456");
try{
subject.login(zhangsan);
System.out.println(subject.isAuthenticated());
}catch (Exception e){
e.getMessage();
}
}
}