Shiro入门学习之散列算法与凭证配置(六)

一、散列算法概述

  散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等,一般进行散列时最好提供一个salt(“盐”),什么意思?举个栗子:加密密码“admin”,产生的散列值是21232f297a57a5a743894a0e4a801fc3,可以到一些md5解密网站(注:并不是真正解密,而是通过穷举法不断尝试)很容易通过散列值得到密码(admin),即如果直接对密码进行散列相对来说破解更容易,此时我们加入一些只有系统知道的干扰数据,如用户名和ID(盐);这样散列对象是“密码+用户名+ID”,这样生成的散列值来说更难破解。

二、凭证配置

  鄙人能力有限,不会叙述其是怎么实现的,有能力的可以自己去百度了。。这里仅仅记录我学习Shiro过程中通过MD5散列算法对密码进行加密,这也是Shiro框架的一部分。

1、新建module,添加如下pom依赖

<properties>
        <shiro.version>1.4.1</shiro.version>
        <loggingg.version>1.2</loggingg.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${loggingg.version}</version>
        </dependency>
    </dependencies>

2、配置凭证

(1)第一种方式:在自定义Realm的构造方法中设置匹配器

 实现如下:

 关键代码如下:

public class UserRealm extends AuthorizingRealm {
    private UserService userService = new UserServiceImpl();
    private RoleService roleService = new RoleServiceImpl();
    private PermissionService permissionService = new PermissionServiceImpl();

    public UserRealm()
    {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //指定加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //指定散列次数
        hashedCredentialsMatcher.setHashIterations(2);
        //这里没有设置salt(盐)的api,为什么这么设计?因为一般salt(盐)存储在数据库
        setCredentialsMatcher(hashedCredentialsMatcher);
    }
    /**
     * 做认证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username1 = token.getPrincipal().toString();
        User user1 = userService.queryUserByUserName(username1);
        if (user1 != null) {
            List<String> roles1 = roleService.queryRoleByUserName(username1);
            List<String> permissions1 = permissionService.queryPermissionByUserName(username1);
            ActivityUser activityUser1 = new ActivityUser(user1, roles1, permissions1);
            System.out.println();
            //参数1:可以传任意对象的|参数2:数据库中的用户密码|参数3:当前类名
            //SimpleAuthenticationInfo info1 = new SimpleAuthenticationInfo(activityUser1, user1.getPwd(), this.getName());
            ByteSource byteSource = ByteSource.Util.bytes("北京");
            SimpleAuthenticationInfo info1 = new SimpleAuthenticationInfo(activityUser1, user1.getPwd(), byteSource, this.getName());
            return info1;
        } else {
            return null;
        }
    }

    //授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        System.out.println("doGetAuthorizationInfo被回调了!");
        //
        Object primaryPrincipal = principal.getPrimaryPrincipal();
        System.out.println(primaryPrincipal);

        ActivityUser activityUser = (ActivityUser) principal.getPrimaryPrincipal();
        List<String> roles = activityUser.getRoles();
        if (roles != null && roles.size() > 0) {
            info.addRoles(roles);
        }
        List<String> permissins = activityUser.getPermissins();
        if (permissins!=null&&permissins.size()>0)
        {
            info.addStringPermissions(permissins);
        }
        //判断如果是超级管理员
        //info.addStringPermission("*:*");
        return info;
    }
}
关键代码

 (2)第2种方式:shiro.ini设置凭证匹配器

 (3)第3种方式:代码中设置凭证匹配器

 关键代码如下:

public class TestAuthorizationRealm
{
    public static void main(String[] args)
    {
        //1.模拟前台传递的用户名和密码
        String username = "zhangsan";
        String password = "123456";
        //2.创建安全管理器的工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //3.通过安全管理器工厂获取安全管理器
        DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance();
        //4.创建自定义的Realm
        UserRealm userRealm = new UserRealm();
        //4.1设置凭证匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //4.2指定加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //4.3指定散列次数
        hashedCredentialsMatcher.setHashIterations(2);
        //4.4这里没有设置salt(盐)的api,为什么这么设计?因为一般salt(盐)存储在数据库
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        //5.设置自定义的Realm
        securityManager.setRealm(userRealm);
        //6.将安全管理器绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //7.从当前环境中获取Subject主体
        Subject subject1 = SecurityUtils.getSubject();
        //8.调用主体的登录方法
        try
        {
            subject1.login(new UsernamePasswordToken(username,password));
            System.out.println("登录成功~");

//            Object principal = subject1.getPrincipal();
//            System.out.println(principal);

        } catch (IncorrectCredentialsException e) {
            System.out.println("密码不正确");
        }catch (UnknownAccountException e) {
            System.out.println("用户名不存在");
        }

        boolean role1 = subject1.hasRole("role1");
        boolean role2 = subject1.hasRole("role1");
        System.out.println(role1);

        boolean permitted = subject1.isPermitted("user:add");
        System.out.println(permitted);
    }
}
关键代码

 三、总结

1、以前我们是拿用户名和密码去匹配数据库中有没有User对象,而在Shiro中是通过用户名查询User对象,将前台获取到的明文进行加密(md5、sha等等)与数据库中的密文密码作比对

2、以上3种设置凭证匹配器本质都是一样的

posted @ 2019-10-31 08:56  coder、  阅读(409)  评论(0编辑  收藏  举报