美文网首页
(三)加密

(三)加密

作者: guideEmotion | 来源:发表于2019-06-22 21:45 被阅读0次

一 加密

md5:非对称加密,既不可逆的
缺陷:相同的明文密码对应的md5加密结果相同,这样穷举法就可以破解
解决办法:盐 和 加密次数。这些都需要保存下来,不同的用户盐也不同

自定义Realm

DAO

package com.how2java;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

/**
 * @author zhuyc
 * @create 2019-06-22 8:14
 */
public class UserDao {
    public UserDao() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=UTF-8", "root",
                "123456");
    }

    public String createUser(String name, String password) {

        String sql = "insert into user values(null,?,?,?)";

        String salt = new SecureRandomNumberGenerator().nextBytes().toString(); //盐量随机
        String encodedPassword= new SimpleHash("md5",password,salt,2).toString();

        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {

            ps.setString(1, name);
            ps.setString(2, encodedPassword);
            ps.setString(3, salt);
            ps.execute();
        } catch (SQLException e) {

            e.printStackTrace();
        }
        return null;

    }

    public String getPassword(String userName) {
        String sql = "select password from user where name = ?";
        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {

            ps.setString(1, userName);

            ResultSet rs = ps.executeQuery();

            if (rs.next())
                return rs.getString("password");

        } catch (SQLException e) {

            e.printStackTrace();
        }
        return null;
    }
    public User getUser(String userName) {
        User user = null;
        String sql = "select * from user where name = ?";
        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {

            ps.setString(1, userName);

            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setPassword(rs.getString("password"));
                user.setSalt(rs.getString("salt"));
            }

        } catch (SQLException e) {

            e.printStackTrace();
        }
        return user;
    }

    public Set<String> listRoles(String userName) {

        Set<String> roles = new HashSet<>();
        String sql = "select r.name from user u "
                + "left join user_role ur on u.id = ur.uid "
                + "left join Role r on r.id = ur.rid "
                + "where u.name = ?";
        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
            ps.setString(1, userName);
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                roles.add(rs.getString(1));
            }

        } catch (SQLException e) {

            e.printStackTrace();
        }
        return roles;
    }
    public Set<String> listPermissions(String userName) {
        Set<String> permissions = new HashSet<>();
        String sql =
                "select p.name from user u "+
                        "left join user_role ru on u.id = ru.uid "+
                        "left join role r on r.id = ru.rid "+
                        "left join role_permission rp on r.id = rp.rid "+
                        "left join permission p on p.id = rp.pid "+
                        "where u.name =?";

        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {

            ps.setString(1, userName);

            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                permissions.add(rs.getString(1));
            }

        } catch (SQLException e) {

            e.printStackTrace();
        }
        return permissions;
    }
}

Realm

package com.how2java;

import java.util.Set;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

public class DatabaseRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //能进入到这里,表示账号已经通过验证了
        String userName =(String) principalCollection.getPrimaryPrincipal();
        //通过DAO获取角色和权限
        Set<String> permissions = new UserDao().listPermissions(userName);
        Set<String> roles = new UserDao().listRoles(userName);

        //授权对象
        SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
        //把通过DAO获取到的角色和权限放进去
        s.setStringPermissions(permissions);
        s.setRoles(roles);
        return s;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取账号密码
        UsernamePasswordToken t = (UsernamePasswordToken) token;
        String userName= token.getPrincipal().toString();
        String password =new String(t.getPassword());
        //获取数据库中的密码

        User user = new UserDao().getUser(userName);
        String passwordInDB = user.getPassword();
        String salt = user.getSalt();
        String passwordEncoded = new SimpleHash("md5",password,salt,2).toString();

        if(null==user || !passwordEncoded.equals(passwordInDB))
            throw new AuthenticationException();

        //认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
        SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(userName,password,getName());
        return a;
    }

}

配置realm

[main]
databaseRealm=com.how2java.DatabaseRealm
securityManager.realms=$databaseRealm

测试类

package com.how2java;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;


/**
 * @author zhuyc
 * @create 2019-06-22 21:22
 */
public class TestShiroEncoder {
    public static void main(String[] args) {
        //这里要释放注释,先注册一个用户
//        new UserDao().createUser("tom", "123");

        User user = new User();
        user.setName("tom");
        user.setPassword("123");

        if(login(user))
            System.out.println("登录成功");
        else
            System.out.println("登录失败");

    }

    private static boolean hasRole(User user, String role) {
        Subject subject = getSubject(user);
        return subject.hasRole(role);
    }

    private static boolean isPermitted(User user, String permit) {
        Subject subject = getSubject(user);
        return subject.isPermitted(permit);
    }

    private static Subject getSubject(User user) {
        //加载配置文件,并获取工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //获取安全管理者实例
        SecurityManager sm = factory.getInstance();
        //将安全管理者放入全局对象
        SecurityUtils.setSecurityManager(sm);
        //全局对象通过安全管理者生成Subject对象
        Subject subject = SecurityUtils.getSubject();

        return subject;
    }

    private static boolean login(User user) {
        Subject subject= getSubject(user);
        //如果已经登录过了,退出
        if(subject.isAuthenticated())
            subject.logout();

        //封装用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());
        try {
            //将用户的数据token 最终传递到Realm中进行对比
            subject.login(token);
        } catch (AuthenticationException e) {
            //验证错误
            return false;
        }

        return subject.isAuthenticated();
    }
}

HashedCredentialsMatcher

上面的做法是做法是自己计算加密后的秘文,再自己比较。 另一个做法是使用Shiro提供的 HashedCredentialsMatcher帮我们做。

修改Realm

其他不改,这里直接放数据库中的加密密码。也不需要我们去比较

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println(this.getCredentialsMatcher());
        //获取账号密码
        UsernamePasswordToken t = (UsernamePasswordToken) token;
        String userName= token.getPrincipal().toString();
        //获取数据库中的密码
         
        User user = new DAO().getUser(userName);
        String passwordInDB = user.getPassword();
        String salt = user.getSalt();
         
        //认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
        //盐也放进去
        //这样通过shiro.ini里配置的 HashedCredentialsMatcher 进行自动校验
        SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(userName,passwordInDB,ByteSource.Util.bytes(salt),getName());
        return a;
    }

修改shiro.ini

为DatabaseRealm 指定credentialsMatcher,其中就指定了算法是 md5, 次数为2, storedCredentialsHexEncoded 这个表示计算之后以密文为16进制。

[main]
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2
credentialsMatcher.storedCredentialsHexEncoded=true

databaseRealm=com.how2java.DatabaseRealm
databaseRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$databaseRealm

参考

  1. http://how2j.cn/k/shiro/shiro-database/1721.html#step7548

相关文章

  • iOS代码加密常用加密方式

    iOS代码加密常用加密方式,常见的iOS代码加密常用加密方式算法包括MD5加密、AES加密、BASE64加密,三大...

  • iOS常用加密方式

    iOS代码加密常用加密方式,常见的iOS代码加密常用加密方式算法包括MD5加密、AES加密、BASE64加密,三大...

  • iOS 几种加密方式

    一:MD5加密 二:base64加密 三:AES加密 四:3DES加密

  • PHP加密算法

    加密技术的重点是加密算法,加密算法主要分为三类: 对称加密 非对称加密 不可逆加密 对称加密算法 加密过程: 将明...

  • (三)加密

    一 加密 md5:非对称加密,既不可逆的缺陷:相同的明文密码对应的md5加密结果相同,这样穷举法就可以破解解决办法...

  • 计算机加密算法总结《概论》

    常见的加密算法可以分成三类,对称加密算法,非对称加密算法和Hash算法。 对称加密 指加密和解密使用相同密钥的加密...

  • IOS 加密

    加密算法 首先了解一下加密算法,常见的加密算法可以分成三类,对称密钥加密、公开密钥加密、散列函数。 对称密钥加密 ...

  • iOS-探究密码学-加密算法特性总结

    加密算法分为三大类:哈希算法、对称加密算法、非对称加密算法。 加密算法特性: 加密算法都是对二进制数据进行加密哦!...

  • IOS开发——各类加密算法总结(MD5,CHA,BASE64,A

    一.MD5加密算法 二.sha1加密算法 三.base64加密算法 四.AES 256加密算法 五.加密算法分析 ...

  • [转]常用加密算法概述

    一. 简述 常见的加密算法可以分成三类,对称加密算法,非对称加密算法和Hash算法。 对称加密指加密和解密使用相同...

网友评论

      本文标题:(三)加密

      本文链接:https://www.haomeiwen.com/subject/psovqctx.html