一,自定义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
时间: 2024-11-10 00:42:28