zoukankan      html  css  js  c++  java
  • Shiro笔记(四)Shiro的realm认证

    认证流程:

    1.获取当前Subject.调用SecurityUtils.getSubject();
    2.测试当前用户是否已经被认证,即是否已经登录,调用Subject的isAurhenticated();
    3.若没有认证,则把用户名和密码封装成UsernamePasswordToken对象.
    对于B/S应用程序来说,一般用户名和密码是在前台表单中获得的:

    1.创建一个表单页面.
    2.把请求提交到SpringMVC的Controller.
    3.获取用户名和密码.

    4.执行登录:调用Subject.login(AuthenticationToken) 方法.
    5.自定义Realm方法,从数据库中获取对应的记录,返回给Shiro.

    自定义Realm的实现:
    1.继承org.apache.shiro.realm.AuthenticatingRealm类.
    2.实现doGetAuthenticationInfo(AuthenticationToken)方法.

    为什么要继承它且实现它的doGetAuthenticationInfo方法呢?可以跟进源码查看subject.login(token)是怎样工作的:
    subject.login(token)->securityManager.login(this, token)->authenticate(token)->authenticator.authenticate(token)->在org.apache.shiro.authc.AbstractAuthenticator中的doAuthenticate(token)方法->查看执行单个认证操作doSingleRealmAuthentication(realms.iterator().next(), authenticationToken)->realm.getAuthenticationInfo(token)->getCachedAuthenticationInfo(token)->在getAuthenticationInfo方法中定义了doGetAuthenticationInfo(token),所以需要实现doGetAuthenticationInfo方法.

    6.由shiro完成对密码的比对.

    数据传输流程解析:

    在执行subject.login(token)方法后,token对象将会传到第5步中自定义Realm中的实现的doGetAuthenticationInfo方法中的AuthenticationToken对象中,这样就可以将token对象传到Realm域中了,我们可以对token进行比对判断登录是否成功.
    流程:

    前台form表单提交数据->Controller->subject.login(token)->shiro域中接收到token对象.

    后台数据验证流程分析

    1. 把AuthenticationToken转换为UsernamePasswordToken.因为我们在之前传入Token对象的时候就是一个这个对象,所以可以强转;

      通过用户名把数据从数据库取出来
      因为配置了Jedis缓存,所以先从缓存中取,取不到再去数据库中取,在数据库中取出后在放到缓存中
      UsernamePasswordToken authenToken = (com.yl.video.security.UsernamePasswordToken) token;

    2. 从UsernamePasswordToken中取出username;

      String userName = token.getUsername();

    3. 调用数据库的方法,从数据库中查询出对应的用户记录,返回一个数据库中的user对象.

      SysUser user = UserUtils.getByLoginName(userName);

    4. 若登录失败,抛出AuthenticationException等异常.此处只抛出一个账户锁定异常.

       if (user != null) {
      
       if (Global.BOOLFALSE.equals(user.getLocked())){
       	throw new AuthenticationException("该已帐号禁止登录.");
       	}
       }
      
    5. 根据用户情况,构建AuthenticationInfo对象并返回.

    AuthenticationInfo对象是一个接口对象,常用SimpleAuthenticationInfo对象来实现.
    创建一个返回的info对象:

    return new SimpleAuthenticationInfo(new Principal(user, authenToken.isMobileLogin()), String.valueOf(user.getPassword()), ByteSource.Util.bytes(userName+user.getSalt()), getName());

    三个参数的解释:

    1. principal:认证的实体信息,可以是传过来的user对象,也可以是username等;
    2. credentials:数据库中的密码;
    3. realmName:当前Realm对象的name,调用父类的getName()方法即可.

    注意:需要对shiro进行登出操作,否则会有登录成功后再登录错误的对象会造成仍然能登录的情况

    密码比对分析

    通过AuthenticatingRealm 的credentialsMatcher 属性来进行密码比对 !

    1. 把密码字符串加密成MD5;
    2. 替换当前Realm的credentialsMatcher属性,直接使用HashedCredentialsMatcher对象,并设置加密算法即可.

    如何替换:
    在对密码加密分析的时候,要对两个密码进行分析,一个是从前台获取到的密码,另一个是在数据库中获取到的密码,分别对两个密码进行盐值加密:

    1. 对从前台传过来的token对象: 通过在配置文件中配置加密算法即可自动将密码加密成想要的结果:








    2. 从数据库中传过来的对象: 因为在shiro的加密中,最后对数据加密是调用了new SimpleHash(hashAlogorithnName,credentials,salt,hashIterations)方法,所以对数据库中的密码直接进行调用此方法即可. 参数分别为(加密方式,加密的密码,盐值,加密次数).

    如何使用盐值加密

    1. 为什么要对密码进行加盐:
      在realm进行密码比对的过程中,当密码相同的时候,用户名无须正确只要密码比对成功即可登录成功,所以要让密码唯一,所以可以对密码加盐,其中盐值必须是唯一的.
    2. 如何对密码进行盐值加密:
      1. 在doGetAuthenticationInfo方法返回值创建SimpleAuthenticationInfo对象的时候,需使用SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName)构造器.
      2. 使用ByteSource.Util.bytes()来计算盐值.
      3. 盐值要唯一:一般使用随机字符串或id
      4. 使用new SimpleHash(hashAlogorithnName,credentials,salt,hashIterations)来计算盐值加密后的值.

    多realm认证

    多realm认证原理:

    多realm认证是通过ModularRealmAuthenticator对象进行认证的,我们可以在spring-shiro中配置多个realm,并将多个bean统一交给ModularRealmAuthenticator进行管理,然后在SecurityManager中配置ModularRealmAuthenticator来进行实现多realm认证的效果。

    多realm的认证配置:

    多realm配置1
    多realm配置2
    多realm配置3

    在多realm配置的时候一般将两个或多个realms放在securityManager中而不是放在authenticator中,如下图:

    这样的好处是当授权的时候比较方便。

    多realm的认证策略

  • 相关阅读:
    struts.custom.i18n.resources 如何配置多个资源文件?
    axis : java.lang.NoSuchMethodError
    org/apache/commons/discovery/tools/DiscoverSingleton
    java.lang.NoClassDefFoundError: javax/wsdl/OperationType
    .propertie文件注释
    数据库的名称尽量要以英文开头,如果全部输数字的话可能会出错的
    单例模式
    java异常 之 异常的层次结构
    php抓取网页
    'hibernate.dialect' must be set when no Connection available
  • 原文地址:https://www.cnblogs.com/esileme/p/7468118.html
Copyright © 2011-2022 走看看