Shiro

$Shiro

Apache-shiro 是一种简便的java安全框架,对于身份认证,授权 。权限管理有着很简单的使用方法

三个核心组件:Subject, SecurityManager 和 Realms.
 
 

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

通过设置加密的密码 存入数据库中 ,并进行加密认证 数据相同时,通过认证。登录成功。

原文地址:https://www.cnblogs.com/CllOVER/p/10386304.html