【Shiro】认证

【知识回顾】
    在上篇博客中,通过对Shiro架构及其组件的总结学习,对Shiro有了一个整体的认识。
    本篇博客将进一步学习其认证组件,Authentication: 身份认证/登录,验证用户是不是拥有相应的身份;
【认证流程图】

                这里写图片描述

【认证流程描述】
        1. 获取当前的Subject,调用SecurityUtils.getSubject();
        2. 测试当前的用户是否已经被认证,即是否已经登录。调用Subject的isAuthenticated();
        3. 若没有被认证,则把用户名和密码封装为UsernamePasswordToken对象;
        4. 执行登录:调用Subject的login(AuthenticationToken)方法;
【环境-需要加入的jar包】

        这里写图片描述

【认证实现1:直接读取用户信息认证】
    1. 流程代码如下:
    /**
     * 用户的登录与退出
     **/
    public void testLoginAndLogout() {

        // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-first.ini");

        // 创建SecurityManager
        SecurityManager securityManager = factory.getInstance();

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

        // 从SecurityUtils里边创建一个subject
        Subject subject = SecurityUtils.getSubject();

        // 测试当前的用户是否已经被认证,即是否已经登录
        // 调用 Subject 的 isAuthenticated() 
        if (!currentUser.isAuthenticated()) {
            // 在认证提交前准备token(令牌)
            // 这里的账号和密码 将来是由用户输入进去
            UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
                "111111");
            try {
                // 执行登录
                currentUser.login(token);
            } 
            // 若没有指定的账户,则shiro会抛出UnknownAccountException异常
            catch (UnknownAccountException uae) {
                log.info("----> There is no user with username of " + token.getPrincipal());
                return; 
            } 
            //若账户存在,但密码不匹配,则会抛出IncorrectCredentialsException异常
            catch (IncorrectCredentialsException ice) {
                log.info("----> Password for account " + token.getPrincipal() + " was incorrect!");
                return; 
            } 
            // 用户被锁定的异常 LockedAccountException
            catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            // 所有认证时异常的父类
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

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

        System.out.println("是否认证通过:" + isAuthenticated);

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

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

        System.out.println("是否认证通过:" + isAuthenticated);

    }   
    2. 流程总结如下:
        此认证流程是直接从shiro-first.ini文件中读取的用户名和密码,shiro-first.ini文件内容如下:
    #对用户信息进行配置
    [users]
    #用户账号和密码
    zhangsan=111111
    lisi=22222
【认证实现2:自定义realm认证】
    代码如上例一样,只需要改下读取的ini文件。
    1. 流程代码如下:
    /**
     * 用户的登录与退出
     **/
    public void testLoginAndLogout() {

        // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-first.ini");
    2. 流程总结如下:
        此方法是通过自定义Realm实现的,实际开发中我们也需要通过realm去查询数据库,获取用户信息。
        CustomRealm代码如下:
public class CustomRealm extends AuthorizingRealm {

    // 设置realm的名称
    @Override
    public void setName(String name) {
        super.setName("customRealm");
    }

    // 用于认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        // token是用户输入的
        // 第一步从token中取出身份信息
        String userCode = (String) token.getPrincipal();

        // 第二步:根据用户输入的userCode从数据库查询
        // ....


        // 如果查询不到返回null
        //数据库中用户账号是zhangsansan
        /*if(!userCode.equals("zhangsansan")){//
            return null;
        }*/


        // 模拟从数据库查询到密码
        String password = "111112";

        // 如果查询到返回认证信息AuthenticationInfo

        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, this.getName());

        return simpleAuthenticationInfo;
    }
}
        shiro-realm.ini文件代码如下:
    [main]
    #自定义realm
    customRealm=com.hzt.shiro.realm.CustomRealm
    #将realm设置到SecurityManager,相当于Spring中注入
    securityManager.realms=$customRealm
【认证实现3:自定义realm,MD5加密认证】
    实际开发中,我们一般都不会直接使用明文,而是会将用户密码进行加密处理,所以我们在自定义realm中,需要进行加密后的值对比。
        CustomRealm添加MD5加密算法,修改代码如下:
public class CustomRealmMd5 extends AuthorizingRealm {

    // 设置realm的名称
    @Override
    public void setName(String name) {
        super.setName("customRealmMd5");
    }

    // 用于认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        // token是用户输入的
        // 第一步从token中取出身份信息
        String userCode = (String) token.getPrincipal();

        // 第二步:根据用户输入的userCode从数据库查询
        // ....

        // 如果查询不到返回null
        // 数据库中用户账号是zhangsansan
        /*
         * if(!userCode.equals("zhangsansan")){// return null; }
         */

        // 模拟从数据库查询到密码,散列值
        String password = "f3694f162729b7d0254c6e40260bf15c";
        // 从数据库获取salt
        String salt = "qwerty";
        //上边散列值和盐对应的明文:111111

        // 如果查询到返回认证信息AuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, ByteSource.Util.bytes(salt), this.getName());

        return simpleAuthenticationInfo;
    }
}
        shiro-realm-MD5.ini文件代码如下:
[main]
    #定义凭证匹配器
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    #散列算法
    credentialsMatcher.hashAlgorithmName=md5
    #散列次数
    credentialsMatcher.hashIterations=1

    #将凭证匹配器设置到realm
    customRealm=com.hzt.shiro.realm.CustomRealmMd5
    customRealm.credentialsMatcher=$credentialsMatcher
    securityManager.realms=$customRealm
【学习总结】
    在本篇博客中,学习到了如何使用shiro去实现认证。在上述应用中,都是测试代码,直接通过读取不同配置的ini文件实现的,而在实际开发中,通常会与spring进行整合,实现原理是一致的,而需要对配置进行些许修改。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值