(转) shiro权限框架详解04-shiro认证

http://blog.csdn.net/facekbook/article/details/54906635

shiro认证

本文介绍shiro的认证功能

  • 认证流程
  • 入门程序(用户登录和退出)
  • 自定义Realm
  • 散列算法

认证流程

开始构造SecurityManager环境subject.login();提交认证securityManager.login()执行认证Authenticator执行认证Realm根据身份获取验证信息结束

入门程序(用户登录和退出)

创建Java项目

jdk版本:1.7.0_67

加入shiro的jar包以及依赖包

log4j.properties日志文件配置

log4j.rootLogger=debug, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

eclipse中ini文件打开方式配置

shiro使用ini文件作为配置文件。所以需要修改eclipse中ini文件的打开方式,默认的话ini文件是使用记事本打开。具体如下图: 

创建ini配置文件

在classpath路径下创建shiro-first.ini文件,文件内容是测试用户的账号和密码。内容如下:

[users]
zhangsan=123
lisi=456

认证代码

@Test
    public void testLoginAndLogOut() {
        // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-first.ini");
        // 通过工厂创建SecurityManager
        SecurityManager securityManager = factory.getInstance();
        // 将SecurityManager设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //创建一个Subject实例,该实例认证需要使用上面创建的SecurityManager
        Subject subject = SecurityUtils.getSubject();
        //创建token令牌,账号和密码是ini文件中配置的
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "123");
        try {
            //用户登录
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
        //用户认证状态
        Boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("用户认证状态:"+isAuthenticated);//输出true

        //用户退出
        subject.logout();

        isAuthenticated = subject.isAuthenticated();
        System.out.println("用户认证状态:"+isAuthenticated);//输出false
    }

认证执行流程

1.创建token令牌,token中有用户提交的认证信息即账号和密码。 
2.执行subject.login(token),最终由securityManager通过 Authenticator进行认证。 
3.Authenticator的实现ModuleRealmAuthenticator调用realm从init文件读取用户真实的账号和密码,这里使用的是IniRealm(Shiro自带) 
4.IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModuleRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。

常见的异常

  • UnknownAccountException 
    账号不存在异常如下:
org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro.realm.text.IniRealm@9cdc393] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - zhangsan1
  • IncorrectCredentialsException 
    当输入密码错误会抛出此异常,如下:
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.

更多异常信息如下: 
DisabledAccountException(帐号被禁用) 
LockedAccountException(帐号被锁定) 
ExcessiveAttemptsException(登录失败次数过多) 
ExpiredCredentialsException(凭证过期)等 
类结构如下图 

自定义Realm

上面的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息。但是实际情况中大部分情况下是从数据库中获取用户信息,所以需要自定义realm。

Shiro中Realm

 
最基础的是Realm接口,CachingRealm负责缓存管理,AuthenticatingRealm负责认证,AuthorizingRealm负责授权,通常自定义的Realm继承AuthorizingRealm。

自定义Realm代码

通过继承AuthorizingRealm类实现

public class CustomRealm extends AuthorizingRealm {

    /**
     * 认证方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        // 从token中获取用户身份信息
        String username = (String) token.getPrincipal();

        // 正常逻辑应该是通过username查询数据库。
        // 如果查询不到返回null
        if (!"zhangsan".equals(username)) {// 这里模仿查询不到
            return null;
        }

        // 模拟从数据获取密码
        String password = "123";

        // 返回认证信息交由父类AuthorizingRealm认证
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, "");

        return authenticationInfo;
    }

    /**
     * 授权方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
}

ini配置文件

新建shiro-realm.ini文件。内容如下:

[main]
#自定义realm
customRealm=com.knight.shiro.realm.CustomRealm
#将realm设置到securityManager
securityManager.realm=$customRealm

这里不需要配置users,是因为我们这里模拟users的获取来自数据库。

测试代码

@Test
    public void testCustomeRealm() {
        // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
        // 通过工厂创建SecurityManager
        SecurityManager securityManager = factory.getInstance();
        // 将SecurityManager设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //创建一个Subject实例,该实例认证需要使用上面创建的SecurityManager
        Subject subject = SecurityUtils.getSubject();
        //创建token令牌,账号和密码是ini文件中配置的
        //AuthenticationToken token = new UsernamePasswordToken("zhangsan", "123");//账号密码正确token
        //AuthenticationToken token = new UsernamePasswordToken("zhangsan", "1234");//密码错误异常token
        AuthenticationToken token = new UsernamePasswordToken("zhangsan1", "123");//账号错误异常token
        try {
            //用户登录
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
        //用户认证状态
        Boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("用户认证状态:"+isAuthenticated);//输出true
    }

散列算法

散列算法一般用于生成一段文本的摘要信息,散列算法不可逆,也就是将内容生成摘要,但是反过来通过摘要生成内容是不可以的。散列算法常用于对密码进行散列,常用的散列算法有MD5、SHA。一般散列算法需要提供一个salt(盐)与原始内容生成摘要,这样做的目的是为了安全性。

例子

        Md5Hash  md5Hash = new Md5Hash("111111");
        System.out.println("md5加密,不加盐:"+md5Hash.toString());

        //md5加密,加盐,一次hash
        String password_md5_sale_1 = new Md5Hash("11111", "aga23", 1).toString();
        System.out.println("md5加密,加盐,一次hash:"+password_md5_sale_1);

        //md5加密,加盐,两次hash
        String password_md5_sale_2 = new Md5Hash("11111", "aga23", 2).toString();
        System.out.println("md5加密,加盐,两次hash:"+password_md5_sale_2);//相当于md5(md5(‘1111‘))

        //使用simpleHash
        String simpleHash = new SimpleHash("MD5", "11111", "aga23", 1).toString();
        System.out.println(simpleHash);

在realm中使用散列算法

实际系统中是将盐和散列后的值存储在数据库中,自定义realm从数据库取出盐和加密后的值由shiro完成密码校验。

自定义支持散列的realm

public class CustomRealmMd5 extends AuthorizingRealm {

    /**
     * 认证方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        // 从token中获取用户身份信息
        String username = (String) token.getPrincipal();

        // 正常逻辑应该是通过username查询数据库。
        // 如果查询不到返回null
        if (!"zhangsan".equals(username)) {// 这里模仿查询不到
            return null;
        }

        // 模拟从数据获取密码
        String password = "fdf907b0d3f427b9ffa2f86f213d1afd";
        // 盐
        String salt = "aga23";
        // 返回认证信息交由父类AuthorizingRealm认证
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password,
                ByteSource.Util.bytes(salt), "");

        return authenticationInfo;
    }

    /**
     * 授权方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
}

支持散列的realm配置

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置散列算法
credentialsMatcher.hashAlgorithmName=md5
#设置散列次数
credentialsMatcher.hashIterations=1

#将凭证匹配器设置到realm
customRealm=com.knight.shiro.realm.CustomRealmMd5
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm

测试代码

注意修改配置文件的路径

    @Test
    public void testCustomeRealmMd5() {
        // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm-md5.ini");
        // 通过工厂创建SecurityManager
        SecurityManager securityManager = factory.getInstance();
        // 将SecurityManager设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //创建一个Subject实例,该实例认证需要使用上面创建的SecurityManager
        Subject subject = SecurityUtils.getSubject();
        //创建token令牌,账号和密码是ini文件中配置的
        //AuthenticationToken token = new UsernamePasswordToken("zhangsan", "11111");//账号密码正确token
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "1234");//密码错误异常token
        //AuthenticationToken token = new UsernamePasswordToken("zhangsan1", "11111");//账号错误异常token
        try {
            //用户登录
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
        //用户认证状态
        Boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("用户认证状态:"+isAuthenticated);//输出true
    }

该文章涉及的代码

代码地址

时间: 2024-12-15 01:33:57

(转) shiro权限框架详解04-shiro认证的相关文章

(转) shiro权限框架详解06-shiro与web项目整合(上)

http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springMVC+mybatis,所以我们是基于搭建好的项目进行改造的. 将shiro整合到web应用中 登录 退出 认证信息在页面展现,也就是显示菜单 shiro的过滤器 将shiro整合到web应用中 数据库脚步 sql脚步放到项目中,项目上传到共享的资源中,文章最后给出共享url. 去除项目中不使用shi

(转)shiro权限框架详解06-shiro与web项目整合(下)

http://blog.csdn.net/facekbook/article/details/54962975 shiro和web项目整合,实现类似真实项目的应用 web项目中认证 web项目中授权 shiro缓存 sessionManager使用 验证码功能实现 记住我功能实现 web项目中认证 实现方式 修改CustomRealm 的 doGetAuthenticationInfo 方法,从数据库中获取用户信息,CustomRealm 返回查询到的用户信息,包括(加密后的密码字符串和salt

(转)shiro权限框架详解05-shiro授权

http://blog.csdn.net/facekbook/article/details/54910606 本文介绍 授权流程 授权方式 授权测试 自定义授权realm 授权流程 开始构造SecurityManager环境subject.isPermitted()授权securityManager.isPermitted()执行授权Authorizer执行授权Realm根据身份获取资源权限信息结束 授权方式 Shiro支持三种方式的授权: 编程式:通过写if/else授权代码块完成. Sub

(转)shiro权限框架详解02-权限理论介绍

http://blog.csdn.net/facekbook/article/details/54893042 权限管理解决方案 本文主要介绍权限管理的解决方法: 粗颗粒度和细颗粒度 基于url拦截 使用权限管理框架 粗颗粒度和细颗粒度 什么是粗颗粒度和细颗粒度 在上一文中提到粗颗粒度和细颗粒度,但是没有细讲. 对资源类型的管理称为粗颗粒度权限管理,既只控制到菜单.按钮.方法,粗颗粒度的例子比如:用户具有用户管理的权限,具有导出订单的权限.对资源实例的控制称为细颗粒度权限管理,既控制到数据级别,

Shiro权限管理详解&lt;转载&gt;

1 权限管理1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源. 权限管理包括用户身份认证和授权两部分,简称认证授权.对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问. 1.2 用户身份认证1.2.1 概念 身份认证,就是判断一个用户是否为合法用户的处理过程.最常用的简单身份认证方式是系统通过核对用户输入的用户名

Shiro权限管理框架详解

https://www.cnblogs.com/jpfss/p/8352031.html 1 权限管理1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源. 权限管理包括用户身份认证和授权两部分,简称认证授权.对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问. 1.2 用户身份认证1.2.1 概念 身份认证,就是判

Shiro权限框架简介

http://blog.csdn.net/xiaoxian8023/article/details/17892041 Shiro权限框架简介 2014-01-05 23:51 3111人阅读 评论(37) 收藏 举报  分类: [java框架](25)  版权声明:本文为博主原创文章,未经博主允许不得转载.如需转载请声明:[转自 http://blog.csdn.net/xiaoxian8023 ] 目录(?)[+] 最近加入了gxpt项目组,被安排做权限模块,所以也有幸第一次接触到了Shiro

shiro权限框架实战

shiro框架作为一种开源的权限框架,通过将身份认证和授权从具体的业务逻辑中分离出来极大地提高了我们的开发速度,它的易用性使得它越来越受到人们的青睐.与之前的ACL权限框架相比,shiro能更容易的实现权限控制,而且作为基于RBAC的权限管理框架通过与shiro标签结合使用,能够让开发人员在更加细粒度的层面上进行控制.举个例子来讲,之前我们使用基于ACL的权限控制大多是控制到连接(这里的连接大家可以简单的认为是页面,下同)层面,也就是通过给用户授权让这个用户对某些连接拥有权限,这种情况显然不太适

shiro权限框架与spring框架轻松整合

2017年06月26日 17:53:30 阅读数:419 shiro是一个权限框架,用于管理网站的权限,大到网站登录过滤,小到一个菜单或按钮是否显示,shiro学习起来非常简单,以下是shiro的执行流程图: 看完不懂的请下载shiro全套视频教程: http://pan.baidu.com/s/1jHOX2MM Subject为当前用户,当它访问系统的时候,就会经过SecurityManager安全管理器,安全管理器类似一个中转站,它实际上会让Realm类来处理用户的认证和授权信息,认证和授权