您的位置:首页 > 其它

Shiro Review——自定义Realm实现认证

2016-06-09 14:19 579 查看

一,自定义Realm

在之前,使用过下面的ini文件进行认证测试:

#对用户信息进行配置
[users]
#用户名跟密码
zhangsan=111111
lisi=111111


里面用户的认证信息是写死的,so,now ,来测试下使用自定义Realm来从我们的DB读取User信息,完成用户认证。

首先大致看下Realm的类层级关系:



比如,我们之前使用ini文件中的users配置用户名跟密码的时候,认证和时候使用的Realm就是IniRealm,比如里面的JdbcRealm,我们可以在数据库里面存储一张表用来认证。。。通常我们自定义Realm继承AuthorizingRealm。

/**
* 自定义Realm
* @author LiuHuiChao
*
*/
public class CustomRealm extends AuthorizingRealm{

@Override
public void setName(String name) {
super.setName("customName");
}

/**
* 认证方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//1,从token中取出用户身份信息
String userCode=(String)token.getPrincipal();

//2,根据用户输入的账号从数据库查询
String password="111111";//模拟从库里查询到的密码

//2--1,查询不到返回null
//2--2,查询到返回AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(userCode,password,this.getName());

return simpleAuthenticationInfo;
}

/**
* 授权方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
return null;
}
}


之后加入一个shiro-realm.ini配置文件:

[main]
#自定义realm
customRealm=cn.itcast.shiro.realm.CustomRealm
#将realm设置到securityManager
securityManager.realms=$customRealm


测试代码:

@Test
public void testCustomRealm() {
// 读取配置文件,初始化SecurityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm.ini");
// 创建SecurityManager
SecurityManager securityManager = factory.getInstance();

// 将SecurityManager设置到当前的运行环境中
SecurityUtils.setSecurityManager(securityManager);

// 从SecurityUtils构造创建一个subject
Subject subject = SecurityUtils.getSubject();

// 在提交认证前,需要准备token
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
"111111");

// 执行认证提交
try {
subject.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
}

boolean IsAuthenticated = subject.isAuthenticated();// 是否认证通过

System.out.println(IsAuthenticated); // ture

// 执行退出操作
subject.logout();

// 是否认证通过
System.out.println(subject.isAuthenticated()); // false

}


ok!!!!~~~

二,自定义Realm支持散列密码验证

在上面的realm进行认证过程中,我们从数据库取出的密码是明文的,这样还是蛮不安全的,正常做法是存入的密码是加密过的,在进行用户认证的时候,对比加密后的密码。

首先来看shrio框架中为我们提供的两个常用散列类:

public static void main(String[] args) {

String source="111111";
String salt="bcss";
int hashCount=2;
//散列一次:210cadc20323b04834132b899a5c2c07
//散列二次:000d9f1f8ce13a0fe52dd4456897eb88

//构造方法中:
//第一个参数:明文,原始密码
//第二个参数:盐,使用随机数
//第三个参数:散列的次数,比如散列两次,相当于md5(md5(...))
Md5Hash md5Hash=new Md5Hash(source,salt,hashCount);
System.out.println(md5Hash.toString());

//第一个参数:散列算法
SimpleHash simpleHash=new SimpleHash("md5",source,salt,hashCount);
System.out.println(simpleHash.toString());

}


我们为 密码明文+salt=>>>>得出密文。这种加盐散列的方式可以防止暴力猜测带来的密码破解。

这样,我们的realm认证方法就变成了:

/**
* 认证方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//1,从token中取出用户身份信息
String userCode=(String)token.getPrincipal();

//2,根据用户输入的账号从数据库查询
String password="210cadc20323b04834132b899a5c2c07";//模拟从库里查询到的密码
String salt="bcss"; //从数据库获取的salt

//2--1,查询不到返回null
//2--2,查询到返回AuthenticationInfo
//SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(userCode,password,this.getName());
SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(userCode,password,ByteSource.Util.bytes(salt),this.getName());
return simpleAuthenticationInfo;
}


为了使用md5进行,还需要在ini配置中加入:

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=1

#将凭证匹配器设置到realm
customRealm=cn.itcast.shiro.realm.CustomRealmWithMd5
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: