在开始之前我想感叹一句,技术久了不回头看看真的会忘记的,这次公司让我重新开发一个程序,项目架构为单体多模块开发,其中有个需求就是需要不同用户表进行登录,且不同表的用户名、手机号都可以重复。

这样的需求是很简单的,但是呢 项目使用了spring security安全框架,刚好这个知识点又忘记了,导致我虽然写了两个登录接口,但是一个表中的用户却能通过另一张表的验证。当时我就想验证逻辑全部自己实现,奈何我有个强迫症,使用一个框架你不压榨它的功能我就会浑身痒痒。于是乎有了这篇文章。

首先你要知道spring security的一些常识,登录验证由AuthenticationManager管理,但是它并不处理实际业务逻辑,它里面包含若干个Authenticationprovider,由provider来处理具体逻辑,只要我们实现多种Authenticationprovider,就能实现多种方式登录。

首先是常规的代码,先来看两个不同的provider

/**
* @Description : 管理员密码验证器
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/28 11:06
*/
@Component
@Slf4j
public class SysUserAuthenticationProvider implements AuthenticationProvider {
@Resource(name = "sysUserDetailsServiceImpl")
private UserDetailsService userDetailsService; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), userDetails.getAuthorities());
} @Override
public boolean supports(Class<?> authentication) {
return authentication.equals(SysUserAuthenticationToken.class);
}
}
/**
* @Description : 用户密码验证器
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/28 12:47
*/
@Component
public class UserAuthenticationProvider implements AuthenticationProvider { @Resource(name = "userDetailsServiceImpl")
private UserDetailsService userDetailsService; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), userDetails.getAuthorities());
} @Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UserAuthenticationToken.class);
}
}

provider的authentication方法处理具体的验证逻辑,那么supports方法是做什么用的呢?没错,在调用authentication方法之前,manager会先去调用supports方法,判断是否给当前provider处理,根据这一点,我们就能够无线扩展自己的逻辑。

后面的authentication方法会去调用UserDetailService,所以这里也需要两个实现类。

/**
* @Description : 移动用户验证处理
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/28 12:48
*/
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService { @Resource
private BusinessUserService businessUserService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
BusinessUser user = businessUserService.queryByUsername(username);
if (StringUtils.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
} else if (user.getStatus().equals(Constants.FALSE)) {
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
}
return createLoginUser(user);
} public UserDetails createLoginUser(BusinessUser user) {
return new MobileUser(user);
}
}
/**
* @Description : 后台用户登录验证处理
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/29 12:38
*/
@Service
@Slf4j
public class SysUserDetailsServiceImpl implements UserDetailsService { @Autowired
private ISysUserService userService; @Autowired
private SysPasswordService passwordService; @Autowired
private SysPermissionService permissionService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user))
{
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
} passwordService.validate(user); return createLoginUser(user);
} public UserDetails createLoginUser(SysUser user)
{
return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
}

我这里做的就是后台用户才有权限,前台用户一视同仁

然后拿出来另外两个类

/**
* @Description : 后台用户
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/28 14:18
*/
public class SysUserAuthenticationToken extends UsernamePasswordAuthenticationToken { /**
* 该方法只是用来选择对应的provider处理器
*/
public SysUserAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
}
/**
* @Description : 前台用户
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/11/28 14:19
*/
public class UserAuthenticationToken extends UsernamePasswordAuthenticationToken {
/**
* 该方法只是用来选择对应的provider处理器
*/
public UserAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
}

可以看到,我只是实现了UsernamePasswordAuthenticationToken类,里面的逻辑没有做任何的改造,也就是说,这两个类只是拿来给manager去判断,然后调用相应的provider去处理逻辑。

至此,最初想解决的不同的登录方式对应不同的表的问题迎刃而解,我们还可以利用这一点,去扩展别的登录方式,例如对接微信登录、支付宝登录,或者是邮箱登录、手机验证码登录等等。

SpringSecurity登录验证,多个用户表的更多相关文章

  1. WebApi用户登录验证及服务器端用户状态存取

    最近项目需要给手机端提供数据,采用WebApi的方式,之前的权限验证设计不是很好,这次采用的是Basic基础认证. 1.常见的认证方式 我们知道,asp.net的认证机制有很多种.对于WebApi也不 ...

  2. springboot+mybatis+shiro项目中使用shiro实现登录用户的权限验证。权限表、角色表、用户表。从不同的表中收集用户的权限、

    要实现的目的:根据登录用户.查询出当前用户具有的所有权限.然后登录系统后.根据查询到的权限信息进行不同的操作. 以下的代码是在搭好的框架之下进行的编码. 文章目录 核心实现部分. 第一种是将用户表和角 ...

  3. SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证

    1 SpirngBoot环境搭建 创建一个SpringBoot项目即可,详情参见三少的相关博文 参考博文 -> 点击前往 SpirngBoot项目脚手架 -> 点击前往 2 引入Spirn ...

  4. python简单实现用户表单登录

    实现简单的用户表单验证登录 user="desperado" pwd=" s=0 for i in range(10): if s < 3: username = ...

  5. mysql 用户表结构设计,第三方登录

    说起用户表,大概是每个应用/网站立项动工(码农们)考虑的第一件事情.用户表结构的设计,算是整个后台架构的基石.如果基石不稳,待到后面需求跟进了发现不能应付,回过头来反复修改用户表,要大大小小作改动的地 ...

  6. 第三百七十三节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表、验证码表、轮播图表

    第三百七十三节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表.验证码表.轮播图表 创建Django项目 项目 settings.py ...

  7. Codeigniter处理用户登录验证后URL跳转

    涉及到My_Controller.php以及登录验证模块User.php,代码如下: My_Controller.php class MY_Controller extends CI_Controll ...

  8. 基于Ajax与用户认证系统的登录验证

    一.登录页面 from django.contrib import admin from django.urls import path from blog import views urlpatte ...

  9. 巨蟒django之CRM1 需求分析&&表结构设计&&注册登录验证

    1.需求分析 .项目 ()业务 ()权限的管理 .CRM customer relationship management 客户关系管理系统 .谁来使用CRM? 销售&&班主任& ...

  10. 如何使用Django实现用户登录验证

    最初开始搞用户登录验证的时候感觉没什么难的,不就是增删改查中的查询数据库么,但是还是遇到许多小问题,而且感觉在查询数据库的时候,要把前端的数据一条一条的进行比对,会导致我的代码很丑,而且方式很不智,所 ...

随机推荐

  1. 写一个PHP单例模式

    1 <?php 2 /** 3 * Created by PhpStorm. 5 * Date: 2019/1/29 6 * Time: 17:44 7 */ 8 9 namespace App ...

  2. 记录坑:Chrome谷歌浏览器最小化和页面遮挡后JS代码不稳定

    问题:用定时器 setInterval()做个滚动通知的动画,浏览器最小化时,定时器 setInterval()失效了,导致滚动条重叠了 可能原因: js代码不稳定 Chrome谷歌浏览器最小化和页面 ...

  3. RabbitMQ学习第七章:消息确认机制之事务机制

    RabbitMQ消息确认机制之事务机制. RabbitMQ中,我们可以通过持久化数据 解决RabbitMQ服务器异常 的数据丢失问题. 问题:生产者将消息发送出去,消息到底有没有到达RabbitMQ服 ...

  4. get与post区别,https协议的通信机制

    get与post区别 幂等的的意思就是一个操作不会修改状态信息,并且每次操作的时候都返回同样的结果.即:做多次提交和做一次的对服务器效果是一样 的. 方法 用法 是否能修改服务器数据 幂等 安全 入参 ...

  5. node_exporter安装

    1.node_exporter下载 node_exporter-1.3.1.linux-amd64.tar.gz tar -xzvf node_exporter-1.3.1.linux-amd64.t ...

  6. 2022-04-12内部群每日三题-清辉PMP

    1.一个项目的成本绩效指数(CPI)为1.2,且关键路径上的一个可交付成果落后于进度. 如果项目经理将项目回正轨,项目会发生什么情况? A.活动将并行执行 B.范围将被修改 C.成本和风险将会增加 D ...

  7. 在element plus中使用checkbox 多选框实现大区省市区选择回选

    1.产品拿来淘宝后台页面,希望我们的快递发货也用这一套 长这样: 2.后端说提供的数据是树形结构,大区id不要传,传省的id,勾选哪个传哪个 3.element  ui的树形插件和级联选择器在数据上是 ...

  8. Linux:服务器(CentOS)搭建FTP服务

    Vsftpd(very secure FTP deamon)是众多Linux发行版中默认的FTP服务器.本文以CentOS 8(腾讯云)服务器为例,使用vsftpd搭建Linux云服务器的FTP服务器 ...

  9. GOF23种设计模式是哪些

    设计模式实践里面提供了许多经久不衰的解决方案和最佳方案.这里,GOF 设计模式主要分为三大类:创建模式.结构模式和行为模式.创建模式对于创建对象实例非常有用.结构模式通过处理类或对象的组合来作用于企业 ...

  10. Jquery_002

    6.$.ajax方法 $.ajax([options]) options是一个json格式的对象,参数是通过键值对的形式存在的 常用的参数如下: async:(默认: true) 默认设置下,所有请求 ...