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;
    }
}
相关推荐
Wang's Blog42 分钟前
Go-Zero项目开发4: 用户服务搜索、详情与统一错误处理
开发语言·golang
我星期八休息1 小时前
网络编程—应用层HTTP协议
linux·运维·开发语言·前端·网络·网络协议·http
梅雅达编程笔记1 小时前
零基础学 Python 第14章 | 模块、包与第三方库
开发语言·python·django·numpy·pandas
Mr__Miss1 小时前
Java泛型完全指南:从入门到精通
java·开发语言·python
赵庆明老师1 小时前
Vben精讲:14-Vben远程加载语言包
开发语言·vben
hehelm2 小时前
AI大模型接入SDK—通用模块设计
linux·开发语言·c++
梅雅达编程笔记4 小时前
零基础学 Python 第15章 | 类与对象:面向对象编程入门
开发语言·python·django·numpy·pandas
行思理4 小时前
微信支付“商家转账用户确认模式”,新手教程
java·开发语言·微信
麻瓜老宋5 小时前
AI开发C语言应用按步走,表达式计算器calc的第一步,中缀表达式词法分析
c语言·开发语言·atomcode
灯澜忆梦5 小时前
GO_文件处理---字符串操作
开发语言·golang