shiro实现密码加密验证的方法及原理

基础的配置不再赘述,仅说明密码加密校验需要增加的配置

1、配置ShiroConfig

  @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //设置加密的次数
        hashedCredentialsMatcher.setHashIterations(5);
        return hashedCredentialsMatcher;
    }

   @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        //设置shiroRealm的密码验证的匹配器
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

2、注册用户的时候密码加密存入数据库

 public AjaxResult register(UserInfo userInfo) {
        String userName = userInfo.getName();
        String password = userInfo.getPassword();
        //判断用户名是否已经存在,如果已存在,那就返回错误信息
        UserInfo selectByUsername = userInfoMapper.selectByUsername(userName);
        if (selectByUsername!=null){
            return AjaxResult.error("改用户名已存在!");
        }
        String salt = new SecureRandomNumberGenerator().nextBytes().toString();
        int times = 5;
        String algorithmName = "md5";
        //SimpleHash类使用md5加密算法加密两次,把盐加进去,生成新的密码
        String encodedPassword = new SimpleHash(algorithmName, password, ByteSource.Util.bytes(salt), times).toString();

        userInfo.setSalt(salt);
        userInfo.setPassword(encodedPassword);
        userInfo.setCreateTime(LocalDateTime.now());
        userInfoMapper.insertSelective(userInfo);
        return AjaxResult.success();
    }

3、登陆的时候使用加密前的密码登陆

配置登陆校验的ShiroRealm 

/**
 * @Description
 * @Author luoss
 * @Date 2021/8/216:35
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 权限信息
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }

    /**
     * 认证信息
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        UserInfo userInfo = userInfoMapper.selectByUsername(username);
        if (userInfo == null){
            throw new AuthenticationException("账号不存在");
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userInfo,userInfo.getPassword(), ByteSource.Util.bytes(userInfo.getSalt()),getName());
        //return的时候进行校验
        return authenticationInfo;
    }

注意:最后的return simpleAuthenticationInfo 的时候就会触发password验证。
我们要知道一个继承关系
shiroRealm----->AuthorizingRealm---->AuthenticatingRealm

当执行"return simpleAuthenticationInfo"之后,会调用AuthenticatingRealm的getAuthenticationInfo()方法

 public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info = this.getCachedAuthenticationInfo(token);
        if (info == null) {
            info = this.doGetAuthenticationInfo(token);
            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                this.cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }

        if (info != null) {
            this.assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }

上面代码中又调用了assertCredentialsMatch(token, info);

protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
        //判断验证是否通过,如果不通过则抛出异常(这个异常将在LoginController中捕获并处理)
            if (!cm.doCredentialsMatch(token, info)) {
                //not successful - throw an exception to indicate this:
                String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                throw new IncorrectCredentialsException(msg);
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                    "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                    "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }
    }

继续看doCredentialsMatch()的源码
调用的是类HashedCredentialsMatcher的方法(在ShiroConfig里设置)

public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        Object tokenHashedCredentials = hashProvidedCredentials(token, info);//这里将得到页面传递来的password通过加密后的结果
        Object accountCredentials = getCredentials(info);//这里得到是数据库的passwrod通过加密后的结果
        return equals(tokenHashedCredentials, accountCredentials);
    }

到这里就可看到password验证的大致流程,
如果返回true,那么验证就通过了。
如何返回false,那么上面的AuthenticatingRealm.assertCredentialsMatch()方法会抛出 IncorrectCredentialsException异常

4、登陆

 @PostMapping("login")
    public AjaxResult login(@RequestBody UserInfo userInfo){
        try {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(userInfo.getName(),userInfo.getPassword());
            subject.login(token);
            return AjaxResult.success();
        }catch (Exception e){
            logger.error("登陆失败:"+e);
            return AjaxResult.error("登陆失败:"+e.getMessage());
        }

    }

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好,以下是 springboot shiro 实现用户登录验证的代码示例: 首先,在 pom.xml 文件中添加以下依赖: ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.6.</version> </dependency> ``` 然后,在 application.yml 文件中配置 shiro 相关信息: ``` shiro: loginUrl: /login successUrl: /index unauthorizedUrl: /unauthorized filterChainDefinitions: /login = anon /logout = logout /** = authc ``` 接着,在 UserRealm 类中实现用户认证和授权: ``` public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); User user = (User) principals.getPrimaryPrincipal(); authorizationInfo.setRoles(user.getRoles()); authorizationInfo.setStringPermissions(user.getPermissions()); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = usernamePasswordToken.getUsername(); User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException("用户名或密码错误"); } return new SimpleAuthenticationInfo(user, user.getPassword(), getName()); } } ``` 最后,在 LoginController 类中处理用户登录请求: ``` @Controller public class LoginController { @PostMapping("/login") public String login(String username, String password) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); return "redirect:/index"; } catch (AuthenticationException e) { return "redirect:/login?error"; } } } ``` 以上就是 springboot shiro 实现用户登录验证的代码示例,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值