做外贸要看哪些网站好,做新浪微博网站需要,php网站开发ppt,成都隆昌网站建设本文章对应视频SpringSecurity6多端账号登录#xff0c;可无限扩展教程#xff0c;记得三连哦#xff0c;这对我很重要呢#xff01; 温馨提示#xff1a;视频与文章相辅相成#xff0c;结合学习效果更强哦#xff01;更多视频教程可移步B站【石添的编程哲学】 SpringSe… 本文章对应视频SpringSecurity6多端账号登录可无限扩展教程记得三连哦这对我很重要呢 温馨提示视频与文章相辅相成结合学习效果更强哦更多视频教程可移步B站【石添的编程哲学】 SpringSecurity实现多表账户登录
需求针对公司员工普通用户等各类型用户将其分别存储在不同的用户表中基于SpeingSecurity实现用户认证也就是登录功能
流程
首先做数据库设计基于SpringBoot创建一个项目项目中做相关的实现通过apifox接口测试工具进行测试分别测试不同用户的登录方法是否调用了对应的登录逻辑【登录也称为认证】 注意权限这块并没有涉及仅仅是用户数据这块 数据表设计
本文先不涉及权限表设计就是两张用户表
员工表
CREATE TABLE ums_sys_user (id bigint NOT NULL AUTO_INCREMENT COMMENT 用户ID,username varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 用户账号,nickname varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 用户昵称,email varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 用户邮箱,mobile varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 手机号码,sex int DEFAULT 0 COMMENT 用户性别0男 1女 2未知,avatar varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 头像地址,password varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 密码,status int DEFAULT 0 COMMENT 帐号状态0正常 1停用,creator bigint DEFAULT 1 COMMENT 创建者,create_time datetime DEFAULT NULL COMMENT 创建时间,updater bigint DEFAULT 1 COMMENT 更新者,update_time datetime DEFAULT NULL COMMENT 更新时间,remark varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 备注,deleted tinyint DEFAULT 0,PRIMARY KEY (id) USING BTREE
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci ROW_FORMATDYNAMIC COMMENT后台用户表;客户表
CREATE TABLE ums_site_user (id bigint NOT NULL AUTO_INCREMENT COMMENT 用户ID,username varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 用户账号,nickname varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 用户昵称,openid varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 微信openid,email varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 用户邮箱,mobile varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 手机号码,sex int DEFAULT 0 COMMENT 用户性别0男 1女 2未知,avatar varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 头像地址,password varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT COMMENT 密码,status int DEFAULT 0 COMMENT 帐号状态0正常 1停用,create_time datetime DEFAULT NULL COMMENT 创建时间,updater bigint DEFAULT 1 COMMENT 更新者,update_time datetime DEFAULT NULL COMMENT 更新时间,remark varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 备注,deleted tinyint DEFAULT 0,PRIMARY KEY (id) USING BTREE
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci ROW_FORMATDYNAMIC COMMENT外部用户表;创建项目
登录功能使用非常简单的三层架构技术选型有
SpringBoot 3.1.XSpringSecurity 6.1.XMybatis Pluslombok【简化实体类】可以通过注解生成getter、setter方法构造方法toString方法等maven
pom文件
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.33/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.3.2/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency
/dependenciesapplication.yml文件配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spring-security?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8username: rootpassword: stt123456创建三层架构
Controller
RestController
RequestMapping(/auth)
public class AuthController {private final ISysUserService sysUserService;private final ISiteUserService siteUserService;public AuthController(ISysUserService sysUserService, ISiteUserService siteUserService) {this.sysUserService sysUserService;this.siteUserService siteUserService;}/*** 后端管理系统登录* 返回值token*/PostMapping(sys_login)public String sysLogin(RequestBody LoginParam loginParam) {return 后台用户登录》 sysUserService.sysLogin(loginParam);}PostMapping(site_login)public String siteLogin(RequestBody LoginParam loginParam) {return APP用户登录》 siteUserService.siteLogin(loginParam);}}SysUserServiceImpl
Service
Slf4j
public class SysUserServiceImpl extends ServiceImplSysUserMapper, SysUser implements ISysUserService {AutowiredQualifier(sysUserAuthenticationManager)private AuthenticationManager authenticationManager;/*** 登录是SpringSecurity实现的我们就是去告诉SpringSecurity现在要登录* SpringSecirity登录是通过 AuthticationManager 实现的* 将AuthticationManager引入到service中调用他的认证方法就可以了* param loginParam* return*/Overridepublic String sysLogin(LoginParam loginParam) {// 通过authenticationManager 的认证方法实现登录该方法需要传入 Authentication 对象 就是一个认证对象// Authenticationl里边存储的就是用户的认证信息权限用户名密码的等信息其实就是loadUserByUsername方法返回的UserDetailsUsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(loginParam.getUsername(), loginParam.getPassword());Authentication authenticate authenticationManager.authenticate(authenticationToken);// 获取用户信息SysUser sysUser (SysUser) authenticate.getPrincipal();log.info(sysUser》{},sysUser);// 返回的是tokenreturn sysUser.getUsername();}
}SiteUserServiceImpl
Service
Slf4j
public class SiteUserServiceImpl extends ServiceImplSiteUserMapper, SiteUser implements ISiteUserService {/*** 将AuthenticationManager注入*/AutowiredQualifier(siteUserAuthenticationManager)private AuthenticationManager authenticationManager;Overridepublic String siteLogin(LoginParam loginParam) {UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(loginParam.getMobile(), loginParam.getPassword());Authentication authenticate authenticationManager.authenticate(authenticationToken);// 强转为用户类型SiteUser siteUser (SiteUser) authenticate.getPrincipal();log.info(siteUser{},siteUser);return siteUser.getUsername();}
}实现login功能
项目中引入SpringSecuritySpringSecurity在实现用户登录【认证】时需要使用到两个接口
UserDetailsService是一个接口 提供了一个方法loadUserByUsername()UserDetails是一个接口用来存储用户权限状态【是否禁用超时等】
通过UserDetailsService查询用户将用户信息放到UserDetails中剩下的就交给SpringSecurity的AuthenticationManager做判断判断用户是否允许登录
分两步走
创建UserDetailsService接口实现类
查询用户分别为客户和用后台系统用户创建对应的查询用户的实现类
// 系统用户的DetailsService
Service
public class SysUserDetailsService implements UserDetailsService {private final SysUserMapper sysUserMapper;public SysUserDetailsService(SysUserMapper sysUserMapper) {this.sysUserMapper sysUserMapper;}/*** 此方法从数据库中查询用户* 返回一个 UserDetails*/Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {log.info(后台系统用户登录》);// 根据用户名查询用户SysUser sysUser sysUserMapper.selectOne(new LambdaQueryWrapperSysUser().eq(SysUser::getUsername, username));// 有权限的话需要查询该用户对应的权限if(sysUser null) {throw new UsernameNotFoundException(用户或密码不正确);}return sysUser;}
}
// APP用户的DetailsService
Slf4j
public class SiteUserDetailsService implements UserDetailsService {private final SiteUserMapper siteUserMapper;public SiteUserDetailsService(SiteUserMapper siteUserMapper) {this.siteUserMapper siteUserMapper;}Overridepublic UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {log.info(APP用户登录》);SiteUser siteUser siteUserMapper.selectOne(new LambdaQueryWrapperSiteUser().eq(SiteUser::getMobile, mobile));if(siteUser null) {throw new UsernameNotFoundException(用户名或密码错误);}return siteUser;}
}创建UserDetails接口实现类
存储用户信息同样的创建两个实现类存储不同的用户信息再实体类上直接修改
// 后台管理系统用户类
TableName(ums_sys_user)
Data
public class SysUser implements Serializable, UserDetails {private Long id;private String username;private String nickname;private String email;private String mobile;private Integer sex;private String avatar;JsonIgnoreprivate String password;private Integer status;private Long creator;private Long updater;private String remark;TableLogicprivate Integer deleted;private LocalDateTime createTime;private LocalDateTime updateTime;Overridepublic Collection? extends GrantedAuthority getAuthorities() {return null;}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;}
}
// APP用户实体类
Data
TableName(ums_site_user)
public class SiteUser implements Serializable, UserDetails {private Long id;private String username;private String nickname;private String openid;private String email;private String mobile;private Integer sex;private String avatar;JsonIgnoreprivate String password;private Integer status;private Long updater;private String remark;TableLogicprivate Integer deleted;private LocalDateTime createTime;private LocalDateTime updateTime;/*** 权限。现在并没有查询权限* return*/Overridepublic Collection? extends GrantedAuthority getAuthorities() {return null;}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;}
}关联
将SpringSecurity的AuthenticationManager 【认证管理器管登录的组件】与我们写的登录逻辑关联起来【loadUserByUsername方法】实现方式就是在SpringSecurity的配置类中实现
/*** 现在使用的是SpringSecurity 6.1.5版本开启SpringSecurity的自定义配置* 需要使用 EnableWebSecurity注解而不再是继承Adpater*/
Configuration
EnableWebSecurity
public class SecurityConfig {Autowiredprivate SysUserDetailsService sysUserDetailsService;Autowiredprivate SiteUserDetailsService siteUserDetailsService;// 配置SpringSecurity的过滤器链Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {// 设置登录接口放行http.authorizeHttpRequests(auth - auth.requestMatchers(/auth/sys_login,/auth/site_login).permitAll().anyRequest().authenticated());// 关闭csrfhttp.csrf(csrf - csrf.disable());return http.build();}// 配置AuthenticationManager配置两个。一个管理后台用户PrimaryBean(sysUserAuthenticationManager)public AuthenticationManager sysUserAuthenticationManager(PasswordEncoder passwordEncoder) {DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider();// 关联UserDetailsServiceauthenticationProvider.setUserDetailsService(sysUserDetailsService);// 关联密码管理器authenticationProvider.setPasswordEncoder(passwordEncoder);return new ProviderManager(authenticationProvider);}// 配置AuthenticationManager管理APP用户Bean(siteUserAuthenticationManager)public AuthenticationManager siteUserAuthenticationManager(PasswordEncoder passwordEncoder) {DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider();// 关联UserDetailsServiceauthenticationProvider.setUserDetailsService(siteUserDetailsService);// 关联密码管理器authenticationProvider.setPasswordEncoder(passwordEncoder);return new ProviderManager(authenticationProvider);}/*** 密码管理器会将明文密码转换成密文加密而且不能解码* return*/Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}密码
需要对数据库中存储的密码进行编码因为SpringSecurity进行密码匹配时会对用户输入的密码先编码再验证先通过PasswordEncoder生成加密后的密码
SpringBootTest
public class MyTestApplication {Autowiredprivate PasswordEncoder passwordEncoder;Testpublic void test() {// 密码加密String encode passwordEncoder.encode(123456);System.out.println(encode);}
}SpringSecurity配置
创建两个AuthenticationManager一定要设置一个主AuthenticationManager否则将会报错即在任意一个Bean上添加Primary注解标记
Primary
Bean(sysAuthenticationManager)
public AuthenticationManager sysAuthenticationManager(PasswordEncoder passwordEncoder) {DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider();authenticationProvider.setUserDetailsService(sysUserDetailsService);authenticationProvider.setPasswordEncoder(passwordEncoder);ProviderManager providerManager new ProviderManager(authenticationProvider);providerManager.setEraseCredentialsAfterAuthentication(false);return providerManager;
}/*** 外部用户验证管理器* param passwordEncoder* return*/
Bean(siteAuthenticationManager)
public AuthenticationManager siteAuthenticationManager(PasswordEncoder passwordEncoder) {DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider();authenticationProvider.setUserDetailsService(siteUserDetailsService);authenticationProvider.setPasswordEncoder(passwordEncoder);ProviderManager providerManager new ProviderManager(authenticationProvider);providerManager.setEraseCredentialsAfterAuthentication(false);return providerManager;
}数据库配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springsecurity?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8username: rootpassword: stt123456AuthenticationManager
AuthenticationManager用于定义SpringSecurity如何进行身份认证之后将认证信息封装在Authentication对象上设置到SecurityContextHolder上AuthenticationManager常用的实现是ProviderManager你也可以对其做自定义实现。