$Shiro
Apache-shiro 是一种简便的java安全框架,对于身份认证,授权 。权限管理有着很简单的使用方法
subject :访问当前系统的用户 主体可以是用户也可以是程序 。
Shrio SecurityManager :安全管理器 ,shiro 的核心。类似于SpringMVC的前端控制器(DispatcherServlet),接收来自 “subject” 的委托,与认证器 ,授权器等进行交互
Realm:相当于dataSource 安全的数据源 充当了shiro 与 数据源 的 “连接器” 当执行认证,授权时,shiro会从realm中比对信息是否合法合理。
Shiro认证(使用ini方式进行测试)---> 所有项目均使用maven方式编写
shiro.ini(创建一个配置文件存放信息 。模拟从数据库中获取信息)
[users] #账号=密码 chen=123 root=10001
新建一个测试类
加载配置文件 获取当前用户信息
通过单独测试编写两个异常信息 ,反馈当用户名出错 或者密码出错的情况,
package com.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; /** * 测试shiro * * @author 18609 * */ public class ShiroTest { @Test public void logintest() { // 创建工厂,加载资源 shiro工厂 调用Factory接口 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini"); // 通过工厂对象创建SecurityManager对象 SecurityManager manager = factory.getInstance(); // 将SecurityManager绑定当前环境中。让系统随时访问SecurityManager对象 SecurityUtils.setSecurityManager(manager); // 创建当前登陆主体 未认证 Subject subject = SecurityUtils.getSubject(); // 收集当前用户信息 UsernamePasswordToken token = new UsernamePasswordToken("root", "10001"); try { subject.login(token); System.out.println("登录成功"); } catch (IncorrectCredentialsException e) { // 密码异常错误 System.out.println("登陆失败,密码错误!"); } catch (UnknownAccountException e) { // 账号异常错误 System.out.println("登陆失败,账号不存在!"); } finally { subject.logout(); System.out.println("注销成功"); } } }
通过token 获取到username 并传给Realm验证 ,如果存在相同数据,封装成如下AuthenticationInfo对象进行返回 否则为null
自定义一个Realm类 继承 AuthenticatingRealm 并复写其类的getName() 实现两个方法 进行认证操作
package com.shiro.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.AuthenticatingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyRealm extends AuthenticatingRealm { // 重写 注意返回值 public String getName() { return "MyRealm"; } // 授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } // 认证 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println(token); // 获取用户名 String username = (String) token.getPrincipal(); // 通过用户名查询 并返回 if (!"root".equals(username)) { return null; } String password = "10001"; // 对比当前信息 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName()); return info; } }
shiro-realm.ini
#自定义realm MyRealm=com.shiro.Realm.MyRealm #指定自定义realm的实现 securityManager.realms=$MyRealm
执行流程
认证成功
Shiro加密认证(使用ini方式进行测试)---> 所有项目均使用maven方式编写
shiro 对md5加密有着较好的支持,这里不说明为什么要进行加密措施。
测试几种加密方法 越往下 加密措施越好。越不易破解(以下加密方式全选用第三种 密码 + salt + 散列次数)
package com.shiro.test; import org.apache.shiro.crypto.hash.Md5Hash; import org.junit.Test; public class Md5Test { @Test public void test() { String password = "10001"; // 密码加密 Md5Hash hash = new Md5Hash(password); System.out.println("password: " + hash); // 密码 + salt(用户名) Md5Hash hash1 = new Md5Hash(password, "root"); System.out.println("passsword + salt :" + hash1); // 密码 + salt(用户名) + 散列次数 安全性能更好 Md5Hash hash2 = new Md5Hash(password, "root", 3); System.out.println("passsword + salt + count :" + hash2); } }
测试类
package com.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; /** * 测试shiro * * @author 18609 * */ public class ShiroTest { @Test public void loginByPasswordtest() { // 创建工厂,加载资源 shiro工厂 调用Factory接口 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-md5.ini"); // 通过工厂对象创建SecurityManager对象 SecurityManager manager = factory.getInstance(); // 将SecurityManager绑定当前环境中。让系统随时访问SecurityManager对象 SecurityUtils.setSecurityManager(manager); // 创建当前登陆主体 未认证 Subject subject = SecurityUtils.getSubject(); // 收集当前用户信息 UsernamePasswordToken token = new UsernamePasswordToken("root", "10001"); try { subject.login(token); System.out.println("登录成功"); } catch (IncorrectCredentialsException e) { // 密码异常错误 System.out.println("登陆失败,密码错误!"); } catch (UnknownAccountException e) { // 账号异常错误 System.out.println("登陆失败,账号不存在!"); } finally { subject.logout(); System.out.println("注销成功"); } } }
新建passwordRealm类 进行加密认证
package com.shiro.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 PasswordRealm extends AuthorizingRealm {
//注意返回值 public String getName() { return "PasswordRealm"; } // 授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } // 认证 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println(token); // 获取用户名 String username = (String) token.getPrincipal(); // 通过用户名查询 并返回 if (!"root".equals(username)) { return null; } // passsword + salt + count :2634402341f810a1007d7c4b4521aef5 String password = "2634402341f810a1007d7c4b4521aef5"; // 对比当前信息 1.用户名 2.密码 3.salt(加盐加密ByteSource.Util.bytes("root")) 4.重写当前的realm名字 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo (username, password, ByteSource.Util.bytes("root"),getName()); return info; } }
ByteSource.Util.bytes("root") :进行盐(salt)加密认证 内填用户名
不写此参数使用salt加密 会报错。报密码错误的问题 因为没有进行用户名认证。
shiro-md5.ini
填写与测试中相关的信息 红色标注不能更改必填项 蓝色标注更改项。
#定义凭证匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #散列算法 credentialsMatcher.hashAlgorithmName=md5 #散列次数 credentialsMatcher.hashIterations=3 #指定passwordRealm的realm myRealm=com.shiro.Realm.PasswordRealm #引用凭证 myRealm.credentialsMatcher=$credentialsMatcher #引用指定realm securityManager.realms=$myRealm
通过设置加密的密码 存入数据库中 ,并进行加密认证 数据相同时,通过认证。登录成功。