SSM框架下shiro的验证码登录

所谓的验证码登录也就是    验证码正确之后利用shiro的免密登录啦

验证码的验证:发送短信的时候,把验证码信息放到缓存里(key为sessionid),表单提交过来的时候,从缓存里拿出来比较就好。

接下来就是shiro 的免密登录:

1、思路

自定义token,在进行授权时判断是密码登陆或无密码登陆,自定义密码认证方法,即写一个方法继承HashedCredentialsMatcher,重写其中的doCredentialsMatch,将其中的token改写为自定义的token,最后将自己写的密码认证方法注入shiro
 

2、源码

1、shiro中有一个类HashedCredentialsMatcher,其中doCredentialsMatch为验证密码的方法

/

2、在ShiroDbRealm中普通登录用的是划红框的UsernamePasswordToken,免密登录的话需要自定义一个Token;

 

3、免密登录

1)创建一个枚举类

public enum LoginType {
    PASSWORD("password"), // 密码登录
    NOPASSWD("nopassword"); // 免密登录

    private String code;

    private LoginType(String code) {
    this.code = code;
    }
    public String getCode () {
    return code;
    }
}

2)自定义Token

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 * 用于免密登录
 */
public class EasyTypeToken extends UsernamePasswordToken {
    
	private static final long serialVersionUID = -775223922389896739L;

    private LoginType type;


    public EasyTypeToken() {
    super();
    }


    public EasyTypeToken(String username, String password, LoginType type, boolean rememberMe,  String host) {
    super(username, password, rememberMe,  host);
    this.type = type;
    }
    /**免密登录*/
    public EasyTypeToken(String username) {
    super(username, "", false, null);
    this.type = LoginType.NOPASSWD;
    }
    /**账号密码登录*/
    public EasyTypeToken(String username, String password) {
    super(username, password, false, null);
    this.type = LoginType.PASSWORD;
    }

    public LoginType getType() {
    return type;
    }


    public void setType(LoginType type) {
    this.type = type;
    }
}

 

3)修改ShiroDbRealm:将UsernamePasswordToen修改为自定义token 

 

4)、重写doCredentialsMatch方法,有其他的限定也可以加进去。

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;

/**
 * 输错5次密码锁定半小时
 * 
 * @author QBK
 */
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher implements InitializingBean {

    private CacheManager cacheManager;
    
    private String retryLimitCacheName;
    private PasswordHash passwordHash;

    public RetryLimitCredentialsMatcher(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    public String getRetryLimitCacheName() {
        return retryLimitCacheName;
    }

    public void setRetryLimitCacheName(String retryLimitCacheName) {
        this.retryLimitCacheName = retryLimitCacheName;
    }

    public void setPasswordHash(PasswordHash passwordHash) {
        this.passwordHash = passwordHash;
    }

   /* @Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
        String username = (String) authcToken.getPrincipal();
        Integer retryCount = getCount(username);
        if (retryCount == null) {
            retryCount = 1;
        } else {
            retryCount++;
        }
        setCount(username, retryCount);
        if (retryCount > 5) {
            throw new ExcessiveAttemptsException();
        }

        boolean matches = super.doCredentialsMatch(authcToken, info);
        if (matches) {
            removeCount(username);
        }
        return matches;
    }*/
    
    @Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
    	/**
    	 * 免密登录
    	 */
    	EasyTypeToken tk = (EasyTypeToken) authcToken;
    	if(tk.getType().equals(LoginType.NOPASSWD)){
    		return true;
    	}else{
    		/**
    		 * 需要密码登录
    		 */
    		return super.doCredentialsMatch(authcToken, info);
    	}
    }
    

    /**
     * @param username
     */
    private void removeCount(String username) {
        cacheManager.getCache(retryLimitCacheName).evict(genKey(username));
    }

    private void setCount(String username, int retryCount) {
        cacheManager.getCache(retryLimitCacheName).put(genKey(username), retryCount);
    }

    private Integer getCount(String username) {
        return cacheManager.getCache(retryLimitCacheName).get(genKey(username),Integer.class);
    }

    private String genKey(String username) {
        return retryLimitCacheName + username;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(passwordHash, "you must set passwordHash!");
        super.setHashAlgorithmName(passwordHash.getAlgorithmName());
        super.setHashIterations(passwordHash.getHashIterations());
    }
}

加到配置里面

 

 

 

5)密码登录:

Subject user = SecurityUtils.getSubject();
EasyTypeToken token = new EasyTypeToken(username, password);
user.login(token);

免密登录:

Subject user = SecurityUtils.getSubject();
EasyTypeToken token = new EasyTypeToken(username);
user.login(token);

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SSM框架中实现登录验证码可以按照以下步骤进行: 1. 添加验证码的依赖: 在项目的`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> ``` 2. 配置验证码生成器: 在Spring的配置文件中,例如`springmvc.xml`,添加以下配置: ```xml <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"> <property name="config"> <bean class="com.google.code.kaptcha.util.Config"> <constructor-arg> <props> <prop key="kaptcha.border">no</prop> <prop key="kaptcha.image.width">120</prop> <prop key="kaptcha.image.height">40</prop> <prop key="kaptcha.textproducer.char.string">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890</prop> <prop key="kaptcha.textproducer.char.length">4</prop> <prop key="kaptcha.textproducer.font.size">30</prop> <prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.NoNoise</prop> </props> </constructor-arg> </bean> </property> </bean> ``` 3. 创建验证码Controller: 创建一个Controller类,用于生成验证码图片和验证用户输入的验证码: ```java import com.google.code.kaptcha.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.IOException; @Controller @RequestMapping("/captcha") public class CaptchaController { @Autowired private Producer captchaProducer; @GetMapping("/image") public void getCaptchaImage(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setDateHeader("Expires", 0); response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); response.addHeader("Cache-Control", "post-check=0, pre-check=0"); response.setHeader("Pragma", "no-cache"); response.setContentType("image/jpeg"); String capText = captchaProducer.createText(); request.getSession().setAttribute("captchaCode", capText); BufferedImage bi = captchaProducer.createImage(capText); ServletOutputStream out = response.getOutputStream(); ImageIO.write(bi, "jpg", out); try { out.flush(); } finally { out.close(); } } @GetMapping("/verify") @ResponseBody public boolean verifyCaptcha(HttpServletRequest request, String captchaCode) { String storedCaptchaCode = (String) request.getSession().getAttribute("captchaCode"); return captchaCode.equalsIgnoreCase(storedCaptchaCode); } } ``` 4. 在登录页面使用验证码: 在登录页面的表单中添加验证码输入框和验证码图片展示,例如: ```html <form action="/login" method="post"> <!-- 其他表单项 --> <div> <label>验证码:</label> <input type="text" name="captchaCode" /> <img src="/captcha/image" onclick="this.src='/captcha/image?'+Math.random()" /> </div> <button type="submit">登录</button> </form> ``` 这里的`/captcha/image`是生成验证码图片的接口地址,点击验证码图片时可以刷新验证码。 5. 在登录操作中验证验证码: 在登录的处理逻辑中,获取用户输入的验证码,并调用验证码验证接口进行验证,例如: ```java @PostMapping("/login") public String login(HttpServletRequest request, String username, String password,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值