Shiro(1)---认证

来源:互联网 发布:java工程师自我评价 编辑:程序博客网 时间:2024/05/19 18:16

0.什么是权限管理

  权限管理是系统的安全范畴,要求必须是合法的用户才可以访问系统(用户认证),且必须具有该 资源的访问权限才可以访问该 资源(授权)。
认证:对用户合法身份的校验,要求必须是合法的用户才可以访问系统。
授权:访问控制,必须具有该 资源的访问权限才可以访问该资源。

这里写图片描述

权限模型

  标准权限数据模型包括 :用户、角色、权限(包括资源和权限)、用户角色关系、角色权限关系。
这里写图片描述

权限分配

  通过UI界面方便给用户分配权限,对上边权限模型进行增、删、改、查操作。

权限控制

  基于角色的权限控制:根据角色判断是否有操作权限,因为角色的变化 性较高,如果角色修改需要修改控制代码,系统可扩展性不强。
  基于资源的权限控制:根据资源权限判断是否有操作权限,因为资源较为固定,如果角色修改或角色中权限修改不需要修改控制代码,使用此方法系统可维护性很强。建议使用。

权限管理的解决方案:

 粗粒度权限管理,对资源类型的权限管理。资源类型比如:菜单、url连接、用户添加页面、用户信息、类方法、页面中按钮。。
粗粒度权限管理比如:超级管理员可以访问户添加页面、用户信息等全部页面。
部门管理员可以访问用户信息页面包括 页面中所有按钮。

 细粒度权限管理,对资源实例的权限管理。资源实例就资源类型的具体化,比如:用户id为001的修改连接,1110班的用户信息、行政部的员工。
细粒度权限管理就是数据级别的权限管理。
细粒度权限管理比如:部门经理只可以访问本部门的员工信息,用户只可以看到自己的菜单,大区经理只能查看本辖区的销售订单。。

粗粒度和细粒度例子:
  系统有一个用户列表查询页面,对用户列表查询分权限,如果粗颗粒管理,张三和李四都有用户列表查询的权限,张三和李四都可以访问用户列表查询。
  进一步进行细颗粒管理,张三(行政部)和李四(开发部)只可以查询自己本部门的用户信息。张三只能查看行政部 的用户信息,李四只能查看开发部门的用户信息。细粒度权限管理就是数据级别的权限管理。

基于url的权限管理(掌握):

  企业开发常用的方法,使用web应用中filter来实现,用户请求url,通过filter拦截,判断用户身份是否合法(用户认证),判断请求的地址是否是用户权限范围内的url(授权)。

1.什么是Shiro

  shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
  spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
  shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。
使用shiro实现系统 的权限管理,有效提高开发效率,从而降低开发成本。

2.Shiro架构

  1. subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。

  2. securityManager:安全管理器,主体进行认证和授权都 是通过securityManager进行。

  3. authenticator:认证器,主体进行认证最终通过authenticator进行的。

  4. authorizer:授权器,主体进行授权最终通过authorizer进行的。

  5. sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。

  6. SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。

  7. cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。

  8. realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。
    注意:在realm中存储认证和授权的逻辑。

  9. cryptography:密码管理,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。
    比如 md5散列算法。

3.jar包

  与其它java开源框架类似,将shiro的jar包加入项目就可以使用shiro提供的功能了。shiro-core是核心包必须选用,还提供了与web整合的shiro-web、与spring整合的shiro-spring、与任务调度quartz整合的shiro-quartz等,下边是shiro各jar包的maven坐标。

        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-core</artifactId>            <version>1.2.3</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-web</artifactId>            <version>1.2.3</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-spring</artifactId>            <version>1.2.3</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-ehcache</artifactId>            <version>1.2.3</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-quartz</artifactId>            <version>1.2.3</version>        </dependency>

4.Shiro认证

认证流程:
这里写图片描述

5.入门程序

配置shiro.ini

#配置数据[users]zhang=123lisi=123

测试代码:

public void testShrio(){        //构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");        //通过工厂创建SecurityManager        SecurityManager securityManager = factory.getInstance();        //将securityManager设置到运行环境中        SecurityUtils.setSecurityManager(securityManager);        //创建一个Subject实例        Subject subject = SecurityUtils.getSubject();        //创建一个token令牌,记录用户认证的身份和凭证即帐号和密码        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123456");        try {            //用户登录            subject.login(token);        } catch (AuthenticationException e) {            e.printStackTrace();        }        //获取用户登录状态        System.out.println("是否认证成功"+subject.isAuthenticated());        subject.logout();        System.out.println("是否认证成功"+subject.isAuthenticated());    }

执行流程:

1.通过ini配置文件创建securityManager

2.调用subject.login方法主体提交认证,提交的token

3. securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。

4.ModularRealmAuthenticator调用IniRealm(给realm传入token) 去ini配置文件中查询用户信息

5.IniRealm根据输入的token(UsernamePasswordToken)从 shiro.ini查询用户信息,根据账号查询用户信息(账号和密码)
  如果查询到用户信息,就给ModularRealmAuthenticator返回AuthenticationInfo(认证信息)。
  如果查询不到,就给ModularRealmAuthenticator返回null

6.ModularRealmAuthenticator接收IniRealm返回的Authentication认证信息
  如果返回的认证信息是null,ModularRealmAuthenticator抛出异常(org.apache.shiro.authc.UnknownAccountException)
  如果返回的认证信息不是null(说明inirealm找到了用户),对IniRealm返回用户密码 (在ini文件中存在)和 token中的密码 进行对比,如果不一致抛出异常(org.apache.shiro.authc.IncorrectCredentialsException)

小结:

ModularRealmAuthenticator作用进行认证,需要调用realm查询用户信息(在数据库中存在用户信息)
ModularRealmAuthenticator进行密码对比(认证过程)。

realm:需要根据token中的身份信息去查询数据库(入门程序使用ini配置文件),如果查到用户返回认证信息,如果查询不到返回null。

6. 自定义realm

1.自定义一个realm类继承AuthorizingRealm类

public class CustomRealm extends AuthorizingRealm {    public String getName() {        return "customRealm";    }    // 授权    protected AuthorizationInfo doGetAuthorizationInfo(            PrincipalCollection principals) {        return null;    }    // 认证    protected AuthenticationInfo doGetAuthenticationInfo(            AuthenticationToken token) throws AuthenticationException {        //从token中获取用户身份信息        String username = (String) token.getPrincipal();        //...模拟从数据库中查询用户帐号是否存在...        //如果查询不到,返回null        if (!"zhang".equals(username)) {            return null;        }        //...模拟从数据库中查询对应的密码...        String password = "111111";        //进行验证,并返回验证信息        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(                username, password, this.getName());        return simpleAuthenticationInfo;    }}

这里写图片描述

2.创建shiro.ini文件

[main]#自定义 realmcustomRealm=com.ak.shiro.CustomRealm#将realm设置到securityManagersecurityManager.realms=$customRealm
在进行测试时,只需修改上述测试代码中载入的ini配置文件即可。

补充:自定义realm类支持散列算法(md5+salt)

对数据加salt后进行md5加密(了解)

    public void testMD5(){        String str1 = new Md5Hash("123456").toString();        System.out.println("123456不加salt:\n"+str1);        //md5加密,加盐,1次散列        String str2 = new Md5Hash("123456", "dsadhfa",1).toString();        System.out.println("123456加salt:\n"+str2);        //md5加密,加盐,2次散列 md5(md5())        String str3 = new Md5Hash("123456", "fadsfdd", 2).toString();        System.out.println("123456加salt:\n"+str3);        String str4 = new SimpleHash("md5", "123456", "fadsfdd", 2).toString();        System.out.println("123456加salt:\n"+str4);    }

实际步骤:

1.修改自定义realm类中的认证方法
在认证时,会对原始密码明文进行加盐加密处理,再做比较认证

// 认证    protected AuthenticationInfo doGetAuthenticationInfo(            AuthenticationToken token) throws AuthenticationException {        String username = (String) token.getPrincipal();        //从数据库中取出md5加密后的密码和salt        String password = "79c02336a80742b2953e15b3269650e7";        String salt = "fadsfdd";        //根据ini文件中的配置进行认证,如散列算法,散列次数        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(                username, password, ByteSource.Util.bytes(salt), this.getName());        return simpleAuthenticationInfo;    }

2.修改shiro.ini文件

[main]#定义凭证匹配器credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher#散列算法credentialsMatcher.hashAlgorithmName=md5#散列次数credentialsMatcher.hashIterations=2#将凭证匹配器设置到realmcustomRealm=com.ak.shiro.CustomRealmMD5customRealm.credentialsMatcher=$credentialsMatchersecurityManager.realms=$customRealm
原创粉丝点击