c.p.api.config.MyAuthenticationProvider

文章目录

sql 复制代码
2025-01-15 14:21:31.017  
WARN 1972 --- [nio-8087-exec-8] 
c.p.api.config.MyAuthenticationProvider  
: 管理员:13524972741 登录失败:密码错误

解释:

  • 时间戳: 2025-01-15 14:21:31.017 - 表示日志记录的时间。
  • 日志级别: WARN - 表示这是一个警告级别的日志。
  • 进程ID: 1972 - 表示发出日志的 Java 进程 ID。
  • 线程信息: [nio-8087-exec-8] - 表示执行日志记录的线程。
  • 类名: c.p.api.config.MyAuthenticationProvider - 表示发出日志的类的完整路径。
  • 日志消息: 管理员:13524972741 登录失败:密码错误 - 表示具体的错误信息,管理员的用户名(这里是电话号码)登录失败,原因是密码错误。

格式化的目的:

通过换行,使得每部分信息都更加清晰独立,更容易阅读和理解。

1、URL

sql 复制代码
 http://127.0.0.1:8087/admin/signIn?username=???&password=???
json 复制代码
{
    "code": 1,
    "msg": "用户名或密码错误"
}

1、AdminController

java 复制代码
@Api(description = "后台用户管理")
@RestController
@RequestMapping("admin")
public class AdminController {

    @PostMapping("signIn")
    @ApiOperation("管理员账号密码登录swagger")
    @PassToken
    public BaseResult signIn(@RequestParam("username") String username,
                             @RequestParam("password") String password) {
        return BaseResult.success();
    }
}
  • 我们发现signIn方法中没有任何逻辑,说明逻辑可能在 Spring Security 配置 中

3、AuthenticationProvider

java 复制代码
package com.productQualification.api.config;

import com.productQualification.user.domain.Admin;
import com.productQualification.user.domain.Role;
import com.productQualification.user.service.AdminCacheService;
import com.productQualification.user.service.RoleCacheService;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    private static Map<String, Date> login = new HashMap<>();
    private static final int LOGIN_INTERVAL = 5;//最小登录间隔

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final Logger loggerAdmin = LoggerFactory.getLogger("ADMIN");

    @Autowired
    private AdminCacheService adminCacheService;

    @Autowired
    private RoleCacheService roleCacheService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 获取用户登录时输入的用户名
        String username = authentication.getName();
        checkLoginInterval(username);
        // 根据用户名查询系统中的用户信息
        Admin admin = adminCacheService.findByUsername(username);
        // 如果用户列表为 null,说明查找用户功能出现异常,抛出 AuthenticationServiceException
        if (null == admin) {
            logger.warn("管理员:{} 登录失败:用户名错误", username);
            throw new BadCredentialsException("用户名或密码错误");
        }

        // 锁定状态
        if (Admin.LOCKED_BY_PASSWORD.equals(admin.getStatus())) {
            if (new Date().after(DateUtils.addHours(admin.getLockedDate(), 24))) {//超过24小时自动解锁
                admin.setStatus(Admin.NORMAL_STATUS);
                admin.setPasswordAttemptCount(0);
                admin.setLockedDate(null);
                adminCacheService.save(admin);
            } else {
                logger.warn("管理员:{} 登录 登录失败:用户密码尝试次数过多 ", username);
                throw new BadCredentialsException("用户密码尝试次数过多,请24小时后再尝试,或找领导解锁");
            }
        }
        if (Admin.LOCKED_BY_LEADER.equals(admin.getStatus())) {
            logger.warn("管理员:{} 登录 登录失败:用户已被上级锁定", username);
            throw new BadCredentialsException("用户已被上级锁定");
        }

        // 密码对比
        String password = (String) authentication.getCredentials();
        if (admin.passwordUnMatches(password)) {
            admin.setPasswordAttemptCount(admin.getPasswordAttemptCount() + 1);
            if (admin.getPasswordAttemptCount() > Admin.PASSWORD_ATTEMPT_MAX_COUNT) {//密码尝试超过上限
                admin.setStatus(Admin.LOCKED_BY_PASSWORD);
                admin.setLockedDate(new Date());
                adminCacheService.save(admin);
                logger.warn("管理员:{} 登录 登录失败:用户密码尝试次数过多", username);
                throw new BadCredentialsException("用户密码尝试次数过多,请24小时后再尝试,或找领导解锁");
            }

            adminCacheService.save(admin);
            logger.warn("管理员:{} 登录失败:密码错误", username);
            throw new BadCredentialsException("用户名或密码错误");
        }
        List<GrantedAuthority> authorities = new ArrayList<>();
        List<Role> roles = roleCacheService.findRolesByAdminId(admin.getId());
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        return new UsernamePasswordAuthenticationToken(authentication, authentication.getCredentials(), authorities);
    }

    private void checkLoginInterval(String username) {
        Date lastLoginDate = login.get(username);
        if (null == lastLoginDate) {
            login.put(username, new Date());
            return;
        }
        if ((System.currentTimeMillis() - lastLoginDate.getTime())/1000 < LOGIN_INTERVAL) {
            throw new BadCredentialsException("登录频率过高");
        } else {
            login.put(username, new Date());
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}
相关推荐
isyangli_blog4 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008114 小时前
FastAPI APIRouter
开发语言·python
Benszen4 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆4 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木4 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充4 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~4 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6165 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草5 小时前
反射、Tomcat执行
java·开发语言
雪的季节6 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt