Shiro 自定义密码验证类

本文详细介绍如何在Shiro框架中自定义密码验证类,以防止重放攻击,包括密码的AES解密过程及与数据库密码的对比规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇 Shiro 重放攻击登录验证 进行表单登录验证

其中,我们可以把在 LoginController 中密码验证的功能提取出来,我们自定义一个密码验证类进行验证,这样可以使我们处理更复杂情况的验证工作。

步骤:

1、将 LoginController 中表单密码验证提取出来,在自定义密码验证类实现

    1)注释其验证工作

	@PostMapping("/login")
	public String login(User user, HttpSession session) {
		//使用 shiro 登录验证
		//1 认证的核心组件:获取 Subject 对象
		Subject subject = SecurityUtils.getSubject();
		
		/*//将密码进行 aes 解密
		String key = (String) session.getAttribute("uuidSalt");
		String iv = (String) session.getAttribute("uuidSalt");
		try {
			user.setPazzword(AesEncryptUtil.desEncrypt(user.getPazzword(), key, iv));
			//密码解码成功后盐值失效
			session.removeAttribute("uuidSalt");
		} catch (Exception e1) {
			e1.printStackTrace();
			return "loginError";
		}*/
		
		//2 将登陆表单封装成 token 对象
		UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPazzword());
		try {
			//3 让 shiro 框架进行登录验证:
			subject.login(token);
		} catch (Exception e) {
			e.printStackTrace();
			return "loginError";
		}
		return "redirect:/admin/index";
	}

    2)自定义密码验证类: extends SimpleCredentialsMatcher

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;

import cn.jq.ssm.utils.AesEncryptUtil;

public class MyCredentialsMatcher extends SimpleCredentialsMatcher{

	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		// 完全由自己定义用户输入的密码,和数据库中的密码的对比规则
		
		UsernamePasswordToken token2 = (UsernamePasswordToken) token;
		String pazzword = new String(token2.getPassword());
		//从服务器中取出uuidSalt(org.apache.shiro.session.Session)
		Session session = SecurityUtils.getSubject().getSession();
 		
		//将密码进行 aes 解密
		String key = (String) session.getAttribute("uuidSalt");
		String iv = (String) session.getAttribute("uuidSalt");
		try {
			pazzword = AesEncryptUtil.desEncrypt(pazzword, key, iv);
			//密码解码成功后盐值失效
			session.removeAttribute("uuidSalt");
		} catch (Exception e) {
			e.printStackTrace();
			throw new IncorrectCredentialsException("受到重放攻击!");
		}
		String formpPzzword = new SimpleHash("MD5", pazzword, "JQSalt", 1024).toString();
		String accountCredentials = String.valueOf(getCredentials(info));
		return formpPzzword.equals(accountCredentials);
	}

    

   重写 doCredentialsMatch 方法: SimpleCredentialsMatcher 使用Object类型,我们使用 String 相等比较(Object没成功,当时值正确,然而ByteSource不正确,待学习),

 

2、 运行项目访问登录即可

 

end ~

### 实现自定义密码验证机制 为了实现在 Apache Shiro 中的自定义密码验证功能,需要创建一个继承 `CredentialsMatcher` 接口的来重写其方法以适应特定需求。下面是一个简单的例子展示如何构建这样的组件。 #### 创建自定义凭证匹配器 首先定义一个新的 Java 作为自定义的凭证匹配器: ```java import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; public class UserPasswordMatcher extends SimpleCredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { // 获取用户输入的密码和存储在数据库中的加密后的密码 String passwordProvided = new String((char[])token.getCredentials()); String hashedPasswordStoredInDb = (String)info.getCredentials(); // 进行密码比较操作,这里可以加入额外的安全措施比如加盐哈希等 return this.equals(hashedPasswordStoredInDb, hashProvidedPassword(passwordProvided)); } private Object hashProvidedPassword(String plainText){ // 对传入明文形式的用户提供密码进行相同方式的散列处理以便于同已存密文对比 // 注意:此处应采用安全算法如PBKDF2WithHmacSHA1、BCrypt或SCrypt,并考虑使用随机数(salt) // 下面仅作示意用途 return simpleHashAlgorithm(plainText); } } ``` 此部分代码展示了如何通过覆写 `doCredentialsMatch()` 方法来自定义密码校验逻辑[^3]。 #### 将自定义凭证匹配器应用到 Realm 接着,在配置文件中指定这个新的匹配器给对应的 realm 使用。这可以通过修改之前提到过的 `ShiroConfig.java` 文件实现: ```java @Configuration public class ShiroConfig { @Bean public UserRealm userRealm(UserPasswordMatcher passwordMatcher) { UserRealm userRealm = new UserRealm(); userRealm.setCredentialsMatcher(passwordMatcher); return userRealm; } // ...其他配置... } ``` 上述代码片段说明了怎样将自定义的 `UserPasswordMatcher` 设置为 `UserRealm` 的属性之一,从而让后者能够利用前者来进行身份验证过程中的密码核对工作。 #### 安全建议 值得注意的是,在实际项目开发过程中应当遵循最佳实践原则确保安全性,例如但不限于: - 不要在客户端传输未经过任何保护措施的数据; - 始终使用强效且被广泛认可的加密/散列函数; - 应用足够的迭代次数以及合适的 salt 来增强基于密码的身份验证系统的强度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值