Shiro的简单使用

流程

Shiro的执行流程:
Subject --> SecurityManager --> Realm

Subject:主体,相当于当前用户,所有用户将由SecurityManager来管理
SecurityManager:安全管理器,它管理着所有 Subject,它是 Shiro 的核心
Realm:域,Shiro 从从 Realm 获取安全数据,SecurityManager需要从Realm中获取数据进行校验

所需依赖

	<dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.7.1</version>
    </dependency>

Shiro 身份验证

在resource目录创建shiro.ini文件

[users]
zhang=123
wang=123

[User]下的键值对形式的数据,左边为帐号,右边为密码。

Test类:验证帐号密码是否正确

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;

public class Test1 {
    public static void main(String[] args) {
        //1、加载配置文件得到安全管理工厂类对象
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2、获取安全管理类对象
        SecurityManager securityManager = factory.getInstance();
        //3、绑定使用的管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4、得到Subject主体用户对象
        Subject subject = SecurityUtils.getSubject();
        //5、及创建用户名/密码身份验证Token(即用户身份/凭证)
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            //6、用户登录,如果不发生异常,用户登录成功
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            /**
             * 如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
             * DisabledAccountException(禁用的帐号)
             * LockedAccountException(锁定的帐号)、
             * UnknownAccountException(错误的帐号)、
             * ExcessiveAttemptsException(登录失败次数过多)、
             * IncorrectCredentialsException (错误的凭证)、
             * ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;
             * 对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,
             * 防止一些恶意用户非法扫描帐号库;
             */
        }
        //7、判断用户登录状态
        boolean authenticated = subject.isAuthenticated();
        if (authenticated) {
            System.out.println("用户登录成功");
        }else {
            System.out.println("用户登录失败");
        }
        subject.logout();
    }
}

执行 subject.login(token)后,shiro根据shiro.ini文件数据进行比对。
注意创建安全管理类对象,这是shiro的核心,我们验证用户登录让主题把用login()方法,其他事情shiro会帮我们搞定。

授权(文件方式)

在resource目录创建shiro.ini文件

[users]
zhang=123,role1,role2
wang=123456
[roles]
role1=user:create,user:update
role2=user:create,user:delete

分配角色,在密码的后用逗号隔开写上拥有的角色
[roles]代表角色,role1代表拥有user角色的create权限和update权限。

Test类:验证权限

import com.entor.realm.RoleRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

public class Test2 {
    public static void main(String[] args) {
        //创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //设置realm对象
        securityManager.setRealm(new RoleRealm());
        //绑定安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //获取用户主体对象
        Subject subject = SecurityUtils.getSubject();
        //创建用户名/密码身份验证Token(即用户身份/凭证)
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
        //7、判断用户登录状态
        boolean authenticated = subject.isAuthenticated();
        if (authenticated) {
            System.out.println("用户登录成功");
        } else {
            System.out.println("用户登录失败");
        }
        boolean role1 = subject.hasRole("role1");
        if (role1) {
            System.out.println("有role1角色");
        } else {
            System.out.println("没有role1角色");
        }
        boolean role2 = subject.hasRole("role2");
        if (role2) {
            System.out.println("有role2角色");
        } else {
            System.out.println("没有role2角色");
        }
        //判断用户是否拥有权限
        boolean permitted = subject.isPermitted("user:create");
        if (permitted) {
            System.out.println("拥有权限user:create");
        } else {
            System.out.println("没有权限user:create");
        }
        permitted = subject.isPermitted("user:delete");
        if (permitted) {
            System.out.println("拥有权限user:delete");
        } else {
            System.out.println("没有权限user:delete");
        }
        subject.logout();
    }
}

自定义Realm(用自定义的Realm来进行认证)

在resource目录创建shiro.ini文件

;声明一个Realm
testRealm=com.entor.realm.TestRealm
;指定securityManager的Realm
securityManager.realms=$testRealm

自定义Realm

import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;

/**
 * 自定义Realm,处理认证逻辑
 */
public class TestRealm implements Realm {
    public String getName() {
        return "TestRealm";
    }

    /**
     * 该Realm支持的Token类型,返回false表示不支持,true表示支持,支持才会执行对应的认证的方法
     *
     * @param token
     * @return
     */
    public boolean supports(AuthenticationToken token) {
        //仅支持UsernamePasswordToken类型的Token
        return token instanceof UsernamePasswordToken;
    }

    /**
     * 认证方法
     */
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
        String password = new String(token1.getPassword());
        if (!username.equals("zhang")) {
            throw new UnknownAccountException("未知用户");
        }

        if (!password.equals("123")) {
            throw new IncorrectCredentialsException("密码错误");
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
        return info;
    }
}

SecurityManager最终调用Realm来处理我们的认证功能,我们可以注入自己的Reaml。

Test1类

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;

public class Test1 {
    public static void main(String[] args) {
        //1、加载配置文件得到安全管理工厂类对象
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2、获取安全管理类对象
        SecurityManager securityManager = factory.getInstance();
        //3、绑定使用的管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4、得到Subject主体用户对象
        Subject subject = SecurityUtils.getSubject();
        //5、及创建用户名/密码身份验证Token(即用户身份/凭证)
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            //6、用户登录,如果不发生异常,用户登录成功
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            /**
             * 如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
             * DisabledAccountException(禁用的帐号)
             * LockedAccountException(锁定的帐号)、
             * UnknownAccountException(错误的帐号)、
             * ExcessiveAttemptsException(登录失败次数过多)、
             * IncorrectCredentialsException (错误的凭证)、
             * ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;
             * 对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,
             * 防止一些恶意用户非法扫描帐号库;
             */
        }
        //7、判断用户登录状态
        boolean authenticated = subject.isAuthenticated();
        if (authenticated) {
            System.out.println("用户登录成功");
        }else {
            System.out.println("用户登录失败");
        }
        subject.logout();
    }
}

自定义AuthorizingRealm来授权

在resource目录创建shiro.ini文件

[main]
;声明一个Realm
roleRealm=com.entor.realm.RoleRealm
;指定securityManager的Realm
securityManager.realm=$roleRealm

自定义AuthorizingRealm:先认证后授权

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.ArrayList;


public class RoleRealm extends AuthorizingRealm {

    /**
     * 获取用户授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取当前登录认证的用户名
        String name = (String) principalCollection.getPrimaryPrincipal();
        //真实做法:根据用户名去数据库查询对应的角色和权限到AuthorizationInfo对象中
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //用户拥有的角色列表
        ArrayList<String> roles = new ArrayList<String>();
        roles.add("role1");
        //用户拥有的权限列表
        ArrayList<String> permission = new ArrayList<String>();
        permission.add("user:create");
        permission.add("user:update");
        //添加角色
        info.addRoles(roles);
        //添加授权
        info.addStringPermissions(permission);
        return info;
    }

    /**
     * 获取用户认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
     	String password = new String(token1.getPassword());
        if (!username.equals("zhang")) {
            throw new UnknownAccountException("未知用户");
        }
        if (!password.equals("123")) {
            throw new IncorrectCredentialsException("密码错误");
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
        return info;
    }
}

TestRole类

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;

public class TestRole {
    public static void main(String[] args) {

        //1、加载配置文件得到安全管理工厂类对象
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-role.ini");
        //2、获取安全管理类对象
        SecurityManager securityManager = factory.getInstance();
        //3、绑定使用的管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4、得到Subject主体用户对象
        Subject subject = SecurityUtils.getSubject();
        //5、创建用户名/密码身份验证Token(即用户身份/凭证)
        String usernmae = "zhang";
        String password = "123";
        String salt = "123456";

        UsernamePasswordToken token = new UsernamePasswordToken(usernmae, password);
        try {
            //6、用户登录,如果不发生异常,用户登录成功
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            /**
             * 如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
             * DisabledAccountException(禁用的帐号)
             * 、LockedAccountException(锁定的帐号)、
             * UnknownAccountException(错误的帐号)、
             * ExcessiveAttemptsException(登录失败次数过多)、
             * IncorrectCredentialsException (错误的凭证)、
             * ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;
             * 对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,
             * 防止一些恶意用户非法扫描帐号库;
             */
        }
        //7、判断用户登录状态
        boolean authenticated = subject.isAuthenticated();
        if (authenticated) {
            System.out.println("用户登录成功");
        } else {
            System.out.println("用户登录失败");
        }
        boolean role1 = subject.hasRole("role1");
        if (role1) {
            System.out.println("有role1角色");
        } else {
            System.out.println("没有role1角色");
        }
        boolean role2 = subject.hasRole("role2");
        if (role2) {
            System.out.println("有role2角色");
        } else {
            System.out.println("没有role2角色");
        }
        //判断用户是否拥有权限
        boolean permitted = subject.isPermitted("user:create");
        if (permitted) {
            System.out.println("拥有权限user:create");
        } else {
            System.out.println("没有权限user:create");
        }
        permitted = subject.isPermitted("user:delete");
        if (permitted) {
            System.out.println("拥有权限user:delete");
        } else {
            System.out.println("没有权限user:delete");
        }
        subject.logout();
    }
}

加密方式

/*      //jdk自带的加密 
        String str = "hello";
        System.out.println("编码前:"+str);
        String encode = java.util.Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));
        System.out.println("编码后:"+encode);
        String decode = Base64.decodeToString(encode);
        System.out.println("解码后:"+decode);*/

/*      //Base64加密  
        String str = "hello";
        System.out.println("编码前:"+str);
        String encode = Base64.encodeToString(str.getBytes(StandardCharsets.UTF_8));
        System.out.println("编码后:"+encode);
        String decode = Base64.decodeToString(encode);
        System.out.println("解码后:"+decode);*/

/*      //使用16进制的方式工具类Hex类编码解码
        String str = "hello";
        System.out.println("编码前:"+str);
        String encode = Hex.encodeToString(str.getBytes());
        System.out.println("编码后:"+encode);
        String decode = new String(Hex.decode(encode.getBytes()));
        System.out.println("解码后:"+decode);*/
        
/*      //MD5加密  
        String str = "hello";
        String salt = "123";
        Md5Hash md5Hash = new Md5Hash(str, salt,1);
        String md5 = md5Hash.toString();//还可以转换为 toBase64()/toHex()
        System.out.println("md5:"+md5);//86fcb4c0551ea48ede7df5ed9626eee7
        System.out.println("base64:"+md5Hash.toBase64());
        System.out.println("hex:"+md5Hash.toHex());*/

        //Shiro 还提供了通用的散列支持
        String str = "hello";
        String salt = "123";
        //内部使用MessageDigest 常用SHA-1 SHA-256 SHA-512 MD5
        String simpleHash = new SimpleHash("SHA-1", str, salt).toString();
        System.out.println(simpleHash);

Shiro加密

在resource目录创建shiro.ini文件

[main]
credentialsMatcher=com.entor.matcher.MyHashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2
credentialsMatcher.storedCredentialsHexEncoded=true
;声明一个Realm
roleRealm=com.entor.realm.RoleRealm
roleRealm.credentialsMatcher=$credentialsMatcher
;指定securityManager的Realm
securityManager.realm=$roleRealm

credentialsMatcher是用来设置加密规则的

加密规则类:MyHashedCredentialsMatcher

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;

/**
 * 自定义密码校验器
 */
public class MyHashedCredentialsMatcher extends HashedCredentialsMatcher {
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        return super.doCredentialsMatch(token, info);
    }
}

自定义AuthorizingRealm 来认证

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.ArrayList;


public class RoleRealm extends AuthorizingRealm {

    /**
     * 获取用户授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取当前登录认证的用户名
        String name = (String) principalCollection.getPrimaryPrincipal();
        //真实做法:根据用户名去数据库查询对应的角色和权限到AuthorizationInfo对象中
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //用户拥有的角色列表
        ArrayList<String> roles = new ArrayList<String>();
        roles.add("role1");
        //用户拥有的权限列表
        ArrayList<String> permission = new ArrayList<String>();
        permission.add("user:create");
        permission.add("user:update");
        //添加角色
        info.addRoles(roles);
        //添加授权
        info.addStringPermissions(permission);
        return null;
    }

    /**
     * 获取用户认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
        String password = "cfb13c831a62c3873ceaa206d7acecc5";
        if (!username.equals("zhang")) {
            throw new UnknownAccountException("未知用户");
        }

//        if (!password.equals("cfb13c831a62c3873ceaa206d7acecc5")) {
//            throw new IncorrectCredentialsException("密码错误");
//        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
        //注入加密的盐,
        info.setCredentialsSalt(ByteSource.Util.bytes(username+123456));
        return info;
    }
}

TestRole类:

public class TestRole {
    public static void main(String[] args) {

        //1、加载配置文件得到安全管理工厂类对象
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-role.ini");
        //2、获取安全管理类对象
        SecurityManager securityManager = factory.getInstance();
        //3、绑定使用的管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4、得到Subject主体用户对象
        Subject subject = SecurityUtils.getSubject();
        //5、创建用户名/密码身份验证Token(即用户身份/凭证)
        String usernmae = "zhang";
        String password = "123";
        String salt = "123456";

/*        //2次md5加密
        password = new SimpleHash("MD5", password, usernmae+salt, 2).toString();
        System.out.println(password);//cfb13c831a62c3873ceaa206d7acecc5*/

        UsernamePasswordToken token = new UsernamePasswordToken(usernmae, password);
        try {
            //6、用户登录,如果不发生异常,用户登录成功
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            /**
             * 如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
             * DisabledAccountException(禁用的帐号)
             * 、LockedAccountException(锁定的帐号)、
             * UnknownAccountException(错误的帐号)、
             * ExcessiveAttemptsException(登录失败次数过多)、
             * IncorrectCredentialsException (错误的凭证)、
             * ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;
             * 对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,
             * 防止一些恶意用户非法扫描帐号库;
             */
        }
        //7、判断用户登录状态
        boolean authenticated = subject.isAuthenticated();
        if (authenticated) {
            System.out.println("用户登录成功");
        } else {
            System.out.println("用户登录失败");
        }
        boolean role1 = subject.hasRole("role1");
        if (role1) {
            System.out.println("有role1角色");
        } else {
            System.out.println("没有role1角色");
        }
        boolean role2 = subject.hasRole("role2");
        if (role2) {
            System.out.println("有role2角色");
        } else {
            System.out.println("没有role2角色");
        }
        //判断用户是否拥有权限
        boolean permitted = subject.isPermitted("user:create");
        if (permitted) {
            System.out.println("拥有权限user:create");
        } else {
            System.out.println("没有权限user:create");
        }
        permitted = subject.isPermitted("user:delete");
        if (permitted) {
            System.out.println("拥有权限user:delete");
        } else {
            System.out.println("没有权限user:delete");
        }
        subject.logout();
    }
}

首先在RoleTest中,我们输入的username=“zhang”,password=“123”,其加载到我们自定义的认证器后doGetAuthenticationInfo方法中假设我们从数据库拿到的密码为:cfb13c831a62c3873ceaa206d7acecc5,我们将用户数据info返回前我们设置了我们的加密时用的盐,当doGetAuthenticationInfo()返回后,shiro会从我们的shiro.ini文件中读取到我们的加密规则和我们设置的盐,这就完成一次加密校验。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值