shiro认证加密流程

一、shiro认证流程

  1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
  2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
  3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
    1). 创建一个表单页面
    2). 把请求提交到 SpringMVC 的 Handler
    3). 获取用户名和密码.
  4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
    @RequestMapping(value = "login",method = RequestMethod.POST)
    public String login(@RequestParam("username") String username,@RequestParam("password") String password){
    	//获取当前subject
        Subject subject = SecurityUtils.getSubject();

        //判断是否有有效凭据来证明了自己的身份,如果没有则进行登录认证
        if(!subject.isAuthenticated()){
            //1、获取提交的用户名以及密码封装为UsernamePasswordToken
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
            try{
                //登录认证
                subject.login(usernamePasswordToken);
            }catch (AuthenticationException ae){ /* 抛出的异常全为AuthenticationException的子类 */
                System.out.println("登陆失败:" + ae.toString());
            }
        }
        return "redirect:list";
    }
  1. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
    1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
    2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法.
  2. 由 shiro 完成对密码的比对.
/**
 * 1. 授权需要继承 AuthorizingRealm 类, 并实现其 doGetAuthorizationInfo 方法
 * 2. AuthorizingRealm 类继承自 AuthenticatingRealm, 但没有实现 AuthenticatingRealm 中的
 * doGetAuthenticationInfo, 所以认证和授权只需要继承 AuthorizingRealm 就可以了. 同时实现他的两个抽象方法.
 */
public class MyRealm extends AuthorizingRealm {
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //将AuthenticationToken强转
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //通过UsernamePasswordToken获取用户名以及密码的信息
        String username = token.getUsername();
        char[] password = token.getPassword();

        //判断查询用户情况,判断是否有改用户
        System.out.println("从数据库获取用户数据");

        //判断用户情况,抛出异常
        //用户不存在,抛出异常
        if ("unknown".equals(username)){
            throw new UnknownAccountException("用户不存在");
        }
        //如果用户被锁定,抛出异常
        if ("monster".equals(username)){
            throw new LockedAccountException("用户被锁定");
        }

        //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
        //以下信息是从数据库中获取的.
        //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
        Object principal = username;
        //2). credentials: 密码.(加密方式在配置文件中通过credentialsMatcher属性配置)
        Object credentials = "e10adc3949ba59abbe56e057f20f883e"; /* 123456的加密结果 MD5加密1次 */

        //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
        String realmName = getName();
        //4). 盐值.(防止用户同密码的状况)
        //通过该方法获取盐值(传入的属性必须是唯一的)
//        ByteSource credentialsSalt = ByteSource.Util.bytes(username);
        //输入的用户名、密码加密后的值、盐值必须和传入的值一样,才可获取认证
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
//        info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
        return info;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

二、加密

  1. 在配置文件中配置加密方式

替换当前 Realm 的 credentialsMatcher 属性. 直接使用 HashedCredentialsMatcher 对象, 并设置加密算法即可.

    <!--
    配置 Realm
    直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->
    <bean id="jdbcRealm" class="com.shiro.test.realm.MyRealm">
        <!-- 通过配置credentialsMatcher属性来,替换realm的加密算法 -->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!-- 指定加密方式 -->
                <property name="hashAlgorithmName" value="MD5"></property>
                <!-- 指定加密次数 -->
                <property name="hashIterations" value="1"></property>
            </bean>
        </property>
    </bean>
  1. 通过使用SimpleAuthenticationInfo来让shiro认证
//通过该方法获取盐值(传入的属性必须是唯一的)
ByteSource.Util.bytes(username);
//传入的用户和密码均为数据库中获得
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
        //盐值加密
//        info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
  1. 可以通过通过使用SimpleHash获取密码加密结果
    @Test
    public void test02(){
        String hashAlgorithmName = "MD5";
        Object credentials = "123456";
        ByteSource salt = ByteSource.Util.bytes("admin");
        int hashIterations = 1;

        Object simpleHash = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        Object simpleHash1 = new SimpleHash(hashAlgorithmName, credentials);

        System.out.println(simpleHash1);
    }
上一篇:git credentials


下一篇:消息队列Rabbitmq