NutzCN Logo
问答 shrio 密码错误也能登录
发布于 1832天前 作者 Hamming 1812 次浏览 复制 上一个帖子 下一个帖子
标签:

首先 创建了 自定义的CaptchaToken

package io.nutz.nutzsite.common.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 * 继承 shiro UsernamePasswordToken
 * 实现 存储验证码
 */
public class CaptchaToken extends UsernamePasswordToken {

	private static final long serialVersionUID = 4676958151524148623L;
	private String captcha;

	public String getCaptcha() {
		return captcha;
	}

	public void setCaptcha(String captcha) {
		this.captcha = captcha;
	}

	public CaptchaToken(String username, String password, boolean rememberMe, String host, String captcha) {
		super(username, password, rememberMe, host);
		this.captcha = captcha;
	}
}

String username = getUsername(request);
		String password = getPassword(request);
		String captcha = getCaptcha(request);
		boolean rememberMe = isRememberMe(request);
		String host = getHost(request);
            Subject subject = SecurityUtils.getSubject();
            ThreadContext.bind(subject);
            subject.login(new CaptchaToken(username, password, rememberMe, host, captcha));
            User user = (User) subject.getPrincipal();

没有异常 就能登录了
UserRealm

package io.nutz.nutzsite.common.shiro;

import io.nutz.nutzsite.common.exception.EmptyCaptchaException;
import io.nutz.nutzsite.common.exception.IncorrectCaptchaException;
import io.nutz.nutzsite.module.sys.models.User;
import io.nutz.nutzsite.module.sys.services.UserService;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.nutz.dao.Cnd;
import org.nutz.integration.shiro.AbstractSimpleAuthorizingRealm;
import org.nutz.integration.shiro.SimpleShiroToken;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;

import java.util.Set;

/**
 * 自定义Realm 处理登录 权限
 */
@IocBean(name = "shiroRealm", fields = "dao")
public class UserRealm extends AbstractSimpleAuthorizingRealm {
    @Inject
    private UserService userService;

    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // null usernames are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        User user = (User) principals.getPrimaryPrincipal();
        if (user == null) {
            return null;
        }
        // 角色列表
        Set<String> roles =userService.getRoleCodeList(user);
        // 功能列表
        Set<String> menus = userService.getPermsByUserId(user.getId());

        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
		auth.setRoles(roles);
		auth.setStringPermissions(menus);
        return auth;
    }

    /**
     * 登录验证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        CaptchaToken authcToken = (CaptchaToken) token;
        String loginname = authcToken.getUsername();
        String captcha = authcToken.getCaptcha();
        if (Strings.isBlank(loginname)) {
            throw Lang.makeThrow(AuthenticationException.class, "Account name is empty");
        }
        User user = dao().fetch(User.class, Cnd.where("login_name","=",loginname));
        if (Lang.isEmpty(user)) {
            throw Lang.makeThrow(UnknownAccountException.class, "Account [ %s ] not found", loginname);
        }
        int errCount = NumberUtils.toInt(Strings.sNull(SecurityUtils.getSubject().getSession(true).getAttribute("errCount")));
        if (errCount > 2) {
            //输错三次显示验证码窗口
            if (Strings.isBlank(captcha)) {
                throw Lang.makeThrow(EmptyCaptchaException.class, "Captcha is empty");
            }
            String captchaTmp = Strings.sBlank(SecurityUtils.getSubject().getSession(true).getAttribute("captcha"));
            if (!authcToken.getCaptcha().equalsIgnoreCase(captchaTmp)) {
                throw Lang.makeThrow(IncorrectCaptchaException.class, "Captcha is error");
            }
        }
        if (user.isStatus()) {
            throw Lang.makeThrow(LockedAccountException.class, "Account [ %s ] is locked.", loginname);
        }
        //设置验证码次数为零
        SecurityUtils.getSubject().getSession(true).setAttribute("errCount", 0);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        return info;
    }

    public UserRealm() {
        this(null, null);
    }

    public UserRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
        // 设置token类型是关键!!!
        setAuthenticationTokenClass(CaptchaToken.class);
    }

    public UserRealm(CacheManager cacheManager) {
        this(cacheManager, null);
    }

    public UserRealm(CredentialsMatcher matcher) {
        this(null, matcher);
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo()
    {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}

11 回复

AbstractSimpleAuthorizingRealm是不验证密码的

不推荐在realm里面验证密码, 在入口方法验证才是正路

一般 执行 subject.login(token); 会报错的 但是 密码不对 也没有 异常 我在检查一下什么情况

        int errCount = 0;
        try {
            //输错三次显示验证码窗口
            errCount = NumberUtils.toInt(Strings.sNull(SecurityUtils.getSubject().getSession(true).getAttribute("errCount")));
            Subject subject = SecurityUtils.getSubject();
            ThreadContext.bind(subject);
            subject.login(token);
            User user = (User) subject.getPrincipal();
            AsyncManager.me().execute(asyncFactory.recordLogininfor(user.getLoginName(), true,"user.login.success"));
            userService.recordLoginInfo(user);
            return Result.success("login.success");
        } catch (IncorrectCaptchaException e) {
            //自定义的验证码错误异常

            return Result.error(1, "login.error.captcha");
        } catch (EmptyCaptchaException e) {
            //验证码为空
            return Result.error(2, "login.error.captcha");
        } catch (LockedAccountException e) {
            return Result.error(3, "login.error.locked");
        } catch (UnknownAccountException e) {
            errCount++;
            SecurityUtils.getSubject().getSession(true).setAttribute("errCount", errCount);
            PrincipalCollection principalCollection =SecurityUtils.getSubject().getPrincipals();

//            AsyncManager.me().execute(asyncFactory.recordLogininfor(, true,"user.login.success"));
            return Result.error(4, "login.error.user");
        } catch (AuthenticationException e) {
            errCount++;
            SecurityUtils.getSubject().getSession(true).setAttribute("errCount", errCount);
            PrincipalCollection principalCollection =SecurityUtils.getSubject().getPrincipals();
            return Result.error(5, "login.error.user");
        } catch (Exception e) {
            errCount++;
            SecurityUtils.getSubject().getSession(true).setAttribute("errCount", errCount);
            PrincipalCollection principalCollection =SecurityUtils.getSubject().getPrincipals();
            return Result.error(6, "login.error.system");
        }

AbstractSimpleAuthorizingRealm 执行login是不会报错的, 除了数据库异常

你想校验就不要继承AbstractSimpleAuthorizingRealm , 继承AuthorizingRealm就行啦, 补个dao属性完事

nutzboot 怎么指定sha256Matcher shiro怎么验证加密盐呢
realm里面设置就行了吗

 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));

shrio 认证策略组 怎么设置呢 AbstractAuthenticationStrategy

也就 assertCredentialsMatch 方法, 按业务写就行了

realm校验密码, 在第三方登录的时候又蛋疼

assertCredentialsMatch 不明白 哪里 设置这个

AuthorizingRealm的方法

密码是设置的

RandomNumberGenerator rng = new SecureRandomNumberGenerator();
        String salt = rng.nextBytes().toBase64();
        setSalt(salt);
        String hashedPasswordBase64 = new Sha256Hash(password, salt, 1024).toBase64();

如何指定 shiro
加密用的什么Md5Hash 还是 Sha256Hash 等等

明白了

    public UserRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        hashedCredentialsMatcher.setHashIterations(1024);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        setAuthenticationTokenClass(CaptchaToken.class);
        setCredentialsMatcher(hashedCredentialsMatcher);
        // 设置token类型是关键!!!
        setAuthenticationTokenClass(CaptchaToken.class);
    }

添加回复
请先登陆
回到顶部