Shiro认证流程

Shiro认证流程

一.shiro认证思路分析

  1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
  2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
  3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
    • 1). 创建一个表单页面
    • 2). 把请求提交到 SpringMVC 的 Handler
    • 3). 获取用户名和密码.
  4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
  5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
    • 1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
    • 2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法.
  6. 由 shiro 完成对密码的比对.

二.实现认证流程

controller实现

@Controller
@RequestMapping("/shiro/")
public class ShiroController {
    @RequestMapping("login")
    public String login(String username , String password){

        //获取subject
        Subject currentUser = SecurityUtils.getSubject();
        //判断用户是否登录
        if(!currentUser.isAuthenticated()){

            //将用户名和密码封装成token对象
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            //实现记住我功能
            token.setRememberMe(true);

            try {
                System.out.println(token.hashCode());
                //执行登录操作
                currentUser.login(token);
            } catch (AuthenticationException e) {
                System.out.println("登录失败:"+e);
            }
        }
        return "redirect:/list.jsp";
    }
}

实现realm

  • 当调用subject调用login(token),实际执行的是realm中的doGetAuthenticationInfo()方法
  • realm实现流程
    • 1.把AuthenticationToken转换为UsernamePasswordToken
    • 2.从token汇总获取username
    • 3.调用数据库的方法,从数据库中查询username的对应用户记录
    • 4.若用户不存在,则可以抛出UnknownAccountException异常
    • 5.根据用户信息情况, 决定是否抛出其他的异常
    • 6.根据哦用户情况,来构建AuthenticationInfo对象并返回
public class SecoundRealm extends AuthenticatingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("secoundRealm");

        //1.把AuthenticationToken转为UsernamePasswordToken

        UsernamePasswordToken uptoken = (UsernamePasswordToken) token;

        //2.从UsernamePasswordToken中获取username

        String username = uptoken.getUsername();

        //3.调用数据库方法,从数据库中取出username对应的用户信息

        System.out.println("从数据库中取出username:"+username+"的所有用户信息");

        //4.若用户不存在,则可以抛出UnknownAccountException异常

        if("unknow".equals(username)){
            throw new UnknownAccountException("用户不存在");
        }

        //5.根据用户信息的情况,决定是否需要抛出其他的AuthenticationExcaptin异常

        if("monster".equals(username)){
            throw new LockedAccountException("用户被锁定");
        }

        //6.根据用户的情况,来构建AuthenticationInfo对象并返回
        //以下信息从数据库中获取
        //1)principal:认证实体的信息 ,可以是username,也可以是数据表中对应的用户实体类对象
        Object principal = username;
        //2)credentials :密码

        Object credentials = null;
        if("admin".equals(username)){
            credentials = "1b257f95ac34ef075aeb3c7b6c00f841a10268f2222";
        }else if("user".equals(username)){
            credentials = "c0ea2ff604cab89d32943d91e2510ce09b176f30";
        }


        //3)realmName:当前realm对象的name,调用父类的getname()方法即可
        String realmName = getName();
        //4)盐值
        ByteSource credentialsSalt = ByteSource.Util.bytes(username);

        SimpleAuthenticationInfo info = null;
        info = new SimpleAuthenticationInfo("secoundRealm",credentials,credentialsSalt,realmName);

        return info;
    }
}

三.密码的比对

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

四.密码的盐值加密

  1. 为什么使用 MD5 盐值加密:
  2. 如何做到:
    1). 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用
    SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器
    2). 使用 ByteSource.Util.bytes() 来计算盐值.
    3). 盐值需要唯一: 一般使用随机字符串或 user id
    4). 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值.

  3. 如何把一个字符串加密为 MD5

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

  • 盐值加密的放阿飞
//通过username来创建盐值
 ByteSource credentialsSalt = ByteSource.Util.bytes(username);

//使用比较复杂的构造器,传入盐值 credentialsSalt
        SimpleAuthenticationInfo info = null;
        info = new SimpleAuthenticationInfo("secoundRealm",credentials,credentialsSalt,realmName);
  • 在配置文件中配置加密的方式和加密的次数
 <bean id="jdbcRealm" class="com.gdy.shiro.ShiroRealm">
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"></property>
                <!--指定加密的次数-->
                <property name="hashIterations" value="1024"></property>
            </bean>
        </property>
    </bean>

五.多realm验证

  • 配置多个realm

    <!--
        3. 配置多个 Realm
        3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->
    <bean id="jdbcRealm" class="com.gdy.shiro.ShiroRealm">
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"></property>
                <!--指定加密的次数-->
                <property name="hashIterations" value="1024"></property>
            </bean>
        </property>
    </bean>
    <bean id="SecoundRealm" class="com.gdy.shiro.SecoundRealm">
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="SHA1"></property>
                <!--指定加密的次数-->
                <property name="hashIterations" value="1024"></property>
            </bean>
        </property>
    </bean>
  • 在securityManager中声明多个realm
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="authenticator" ref="authenticator"></property>
        <property name="realms">
            <list>
                <ref bean="jdbcRealm"></ref>
                <ref bean="SecoundRealm"></ref>
            </list>
        </property>
    </bean>
  • 配置认证策略

AuthenticationStrategy 接口的默认实现:
- FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
- AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可, 和FirstSuccessfulStrategy 不同,将返回所有Realm身份验证成功的认证信
息;
- AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
- ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy策略

   <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        <!--认证策略-->
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
        </property>
    </bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值