shiro自定义密码匹配验证,密码加密验证

更改shiro安全管理配置

src/main/resources/spring-context-shiro.xml 其他非关键代码省略

...
    <!-- 定义Shiro安全管理配置 -->
    <bean id="systemAuthorizingRealm" class="com.manage.security.SystemAuthorizingRealm"/>
...

SystemAuthorizingRealm 代码

关键点1:

RetryLimitSimpleCredentialsMatcher 需要继承 SimpleCredentialsMatcher,不能继承HashedCredentialsMatcher (本人没有探究原因)

关键点2

SimpleAuthenticationInfo 的参数根据需要调整

PasswordHelper/validatePassword/2

    /**
     * 验证密码
     *
     * @param plainPassword 明文密码
     * @param password      密文密码
     * @return 验证成功返回true
     */
    public static boolean validatePassword(String plainPassword, String password) {
        String plain = EncodeUtils.unescapeHtml(plainPassword);
        if (password.substring(0, DigestUtils.PBKDF2_SHA256.length()).equals(DigestUtils.PBKDF2_SHA256)) {
            return  DigestUtils.pbkdf2_sha256_verify(plain, password);
        }
        byte[] salt = getSalt(password, HASH_ALGORITHM);

        byte[] hashPassword = null;
        if (HASH_ALGORITHM.equals(DigestUtils.MD5)) {
            hashPassword = DigestUtils.md5(plain.getBytes(), salt, HASH_INTERATIONS);
        } else if (HASH_ALGORITHM.equals(DigestUtils.SHA1)) {
            hashPassword = DigestUtils.sha1(plain.getBytes(), salt, HASH_INTERATIONS);
        }
        String tmpPwd = EncodeUtils.encodeHex(hashPassword);
        if (salt != null) {
            tmpPwd = EncodeUtils.encodeHex(salt) + tmpPwd;
        }
        return password.equals(tmpPwd);
    }

SystemAuthorizingRealm 和 RetryLimitSimpleCredentialsMatcher 类

package com.manage.security;

import com.common.dict.ExpireTime;
import com.common.exception.BussinessException;
import com.common.security.shiro.UsernamePasswordToken;
import com.common.util.EncodeUtils;
import com.common.util.PasswordHelper;
import com.common.util.RSAEncrypt;
import com.common.util.StringUtils;
import com.core.core.constant.ConfigConstant;
import com.core.core.constant.Constant;
import com.core.core.constant.ResourceConstant;
import com.core.core.util.CacheUtils;
import com.core.core.util.ConfigUtils;
import com.core.core.util.ResourceUtils;
import com.core.core.util.ValidateUtils;
import com.core.sys.domain.Operator;
import com.core.sys.service.OperatorService;

import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicInteger;

import com.rd.ifaes.common.util.code.Converter;

//@Service
public class SystemAuthorizingRealm extends AuthorizingRealm {

    private static final Logger LOGGER = LoggerFactory.getLogger(SystemAuthorizingRealm.class);
    /**
     * 登录失败缓存key前缀
     */
    private static final String LOGIN_FAIL = "loginFail:";
    @Autowired
    private OperatorService operatorService;

    /**
     * 认证回调函数, 登录时调用
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        LOGGER.debug("login submit  username: {}", token.getUsername());

        // 验证码校验
        String vCode = StringUtils.isNull(token.getCaptcha());
        if (vCode.isEmpty()) {
            throw new BussinessException(ResourceUtils.get(ResourceConstant.VALID_CODE_NOTEMPTY),
                    BussinessException.TYPE_JSON);
        }

        if (!ValidateUtils.checkValidCode(vCode)) {
            throw new BussinessException(ResourceUtils.get(ResourceConstant.VALID_CODE_ERROR),
                    BussinessException.TYPE_JSON);
        }
        //账户校验
        Operator user = operatorService.getByLoginName(token.getUsername());
        if (user == null || (user.getDeleteFlag() != null && Operator.ROLE_EQ.equals(user.getDeleteFlag()))) {
            throw new UnknownAccountException();//没找到帐号
        }

        int formEncryptEnable = ConfigUtils.getInt(ConfigConstant.USER_LOGIN_FORM_ENCRYPT_ENABLE);
        //对页面加密密码进行解密
        if(formEncryptEnable == Constant.INT_ONE && token.getEncrypt() == Constant.INT_ONE){
            String privateKey = ConfigUtils.getValue("rsa_private_key_pkcs8");
            try {
                byte[] pwd = RSAEncrypt.decrypt(
                    RSAEncrypt.loadPrivateKeyByStr(privateKey),
                    new BASE64Decoder().decodeBuffer(String.valueOf(token.getPassword()))
                );
                token.setPassword(Converter.bytesToChars(pwd));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 密码校验
        String cacheKey = LOGIN_FAIL + token.getUsername();
        AtomicInteger loginFailNum = CacheUtils.get(cacheKey, AtomicInteger.class);
        if (loginFailNum == null) {
            loginFailNum = new AtomicInteger(0);
        }
        if (loginFailNum.incrementAndGet() >= 5) {
            throw new BussinessException(ResourceUtils.get(ResourceConstant.OPERATOR_IS_LOCKED),
                    BussinessException.TYPE_JSON);
        }
        CacheUtils.set(cacheKey, loginFailNum, ExpireTime.ONE_DAY);

        return new SimpleAuthenticationInfo(
                user, user.getPwd(),
                ByteSource.Util.bytes("".getBytes()), getName());
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection authcToken) {
        Operator user = (Operator) authcToken.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(operatorService.findRoles(user.getUuid()));
        info.setStringPermissions(operatorService.findPermissions(user.getUuid()));
        return info;
    }

    @Override
    public String getName() {
        return "systemAuthorizingRealm";
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

    /**
     * 设定密码校验的Hash算法与迭代次数
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        setCredentialsMatcher(new RetryLimitSimpleCredentialsMatcher());
    }

    class RetryLimitSimpleCredentialsMatcher extends SimpleCredentialsMatcher {
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            UsernamePasswordToken uptoken = (UsernamePasswordToken) token;
            String userName = uptoken.getUsername();

            String plainPassword = String.valueOf(uptoken.getPassword());
            String password = String.valueOf(getCredentials(info));

            boolean matches = PasswordHelper.validatePassword(plainPassword, password);
            if (matches) {
                //clear retry count
                CacheUtils.del(LOGIN_FAIL + userName);
            }
            return matches;
        }
    }
}

猜你喜欢

转载自my.oschina.net/leeyisoft/blog/1787417