欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity多表多端賬戶登錄的實現(xiàn)

 更新時間:2024年05月14日 09:48:43   作者:石添的編程哲學(xué)  
本文主要介紹了SpringSecurity多表多端賬戶登錄的實現(xiàn)

需求:針對公司員工,普通用戶等各類型用戶,將其分別存儲在不同的用戶表中,基于SpeingSecurity實現(xiàn)用戶認(rèn)證,也就是登錄功能

流程

  • 首先做數(shù)據(jù)庫設(shè)計
  • 基于SpringBoot創(chuàng)建一個項目
  • 項目中做相關(guān)的實現(xiàn)
  • 通過apifox接口測試工具進行測試
  • 分別測試不同用戶的登錄方法,是否調(diào)用了對應(yīng)的登錄邏輯【登錄也稱為認(rèn)證】

注意:權(quán)限這塊并沒有涉及,僅僅是用戶數(shù)據(jù)這塊

數(shù)據(jù)表設(shè)計

本文先不涉及權(quán)限,表設(shè)計就是兩張用戶表

員工表

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 '帳號狀態(tài)(0正常 1停用)',
  `creator` bigint DEFAULT '1' COMMENT '創(chuàng)建者',
  `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時間',
  `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
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC 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 '帳號狀態(tài)(0正常 1停用)',
  `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時間',
  `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
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='外部用戶表';

創(chuàng)建項目

登錄功能,使用非常簡單的三層架構(gòu),技術(shù)選型有:

  • SpringBoot 3.1.X
  • SpringSecurity 6.1.X
  • Mybatis Plus
  • lombok【簡化實體類】,可以通過注解生成getter、setter方法,構(gòu)造方法,toString方法等
  • maven

pom文件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

application.yml文件配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring-security?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: stt123456

創(chuàng)建三層架構(gòu)

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;
    }

    /**
     * 后端管理系統(tǒng)登錄
     * 返回值: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 ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    @Qualifier("sysUserAuthenticationManager")
    private AuthenticationManager authenticationManager;

    /**
     * 登錄是SpringSecurity實現(xiàn)的,我們就是去告訴SpringSecurity現(xiàn)在要登錄
     * SpringSecirity登錄是通過 AuthticationManager 實現(xiàn)的
     * 將AuthticationManager引入到service中,調(diào)用他的認(rèn)證方法就可以了
     * @param loginParam
     * @return
     */
    @Override
    public String sysLogin(LoginParam loginParam) {
        // 通過authenticationManager 的認(rèn)證方法實現(xiàn)登錄,該方法需要傳入 Authentication 對象 就是一個認(rèn)證對象
        // Authenticationl里邊存儲的就是用戶的認(rèn)證信息,權(quán)限,用戶名,密碼的等信息,其實就是loadUserByUsername方法返回的UserDetails
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginParam.getUsername(), loginParam.getPassword());

        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        // 獲取用戶信息
        SysUser sysUser = (SysUser) authenticate.getPrincipal();
        log.info("sysUser==========》{}",sysUser);
        // 返回的是token
        return sysUser.getUsername();
    }
}

SiteUserServiceImpl

@Service
@Slf4j
public class SiteUserServiceImpl extends ServiceImpl<SiteUserMapper, SiteUser> implements ISiteUserService {

    /**
     * 將AuthenticationManager注入
     */
    @Autowired
    @Qualifier("siteUserAuthenticationManager")
    private AuthenticationManager authenticationManager;

    @Override
    public String siteLogin(LoginParam loginParam) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginParam.getMobile(), loginParam.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        // 強轉(zhuǎn)為用戶類型
        SiteUser siteUser = (SiteUser) authenticate.getPrincipal();
        log.info("siteUser===========>{}",siteUser);
        return siteUser.getUsername();
    }
}

實現(xiàn)login功能

項目中引入SpringSecurity,SpringSecurity在實現(xiàn)用戶登錄【認(rèn)證】時需要使用到兩個接口

  • UserDetailsService:是一個接口 ,提供了一個方法loadUserByUsername();
  • UserDetails:是一個接口,用來存儲用戶權(quán)限,狀態(tài)【是否禁用,超時等】

通過UserDetailsService查詢用戶,將用戶信息放到UserDetails中,剩下的就交給SpringSecurity的AuthenticationManager做判斷,判斷用戶是否允許登錄

分兩步走

創(chuàng)建UserDetailsService接口實現(xiàn)類

查詢用戶,分別為客戶和用后臺系統(tǒng)用戶創(chuàng)建對應(yīng)的查詢用戶的實現(xiàn)類

// 系統(tǒng)用戶的DetailsService
@Service
public class SysUserDetailsService implements UserDetailsService {

    private final SysUserMapper sysUserMapper;

    public SysUserDetailsService(SysUserMapper sysUserMapper) {
        this.sysUserMapper = sysUserMapper;
    }

    /**
     * 此方法從數(shù)據(jù)庫中查詢用戶
     * 返回一個 UserDetails
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("后臺系統(tǒng)用戶登錄=============》");
        // 根據(jù)用戶名查詢用戶
        SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
        // 有權(quán)限的話,需要查詢該用戶對應(yīng)的權(quán)限
        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;
    }

    @Override
    public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
        log.info("APP用戶登錄===================》");
        SiteUser siteUser = siteUserMapper.selectOne(new LambdaQueryWrapper<SiteUser>().eq(SiteUser::getMobile, mobile));
        if(siteUser == null) {
            throw new UsernameNotFoundException("用戶名或密碼錯誤!");
        }
        return siteUser;
    }
}

創(chuàng)建UserDetails接口實現(xiàn)類

存儲用戶信息,同樣的創(chuàng)建兩個實現(xiàn)類,存儲不同的用戶信息,再實體類上直接修改

// 后臺管理系統(tǒng)用戶類
@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;
    @JsonIgnore
    private String password;
    private Integer status;
    private Long creator;
    private Long updater;
    private String remark;
    @TableLogic
    private Integer deleted;

    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public 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;
    @JsonIgnore
    private String password;
    private Integer status;
    private Long updater;
    private String remark;
    @TableLogic
    private Integer deleted;

    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    /**
     * 權(quán)限?,F(xiàn)在并沒有查詢權(quán)限
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

關(guān)聯(lián)

將SpringSecurity的AuthenticationManager 【認(rèn)證管理器,管登錄的組件】,與我們寫的登錄邏輯關(guān)聯(lián)起來【loadUserByUsername方法】,實現(xiàn)方式就是在SpringSecurity的配置類中實現(xiàn)

/**
 * 現(xiàn)在使用的是SpringSecurity 6.1.5版本,開啟SpringSecurity的自定義配置,
 * 需要使用 @EnableWebSecurity注解,而不再是繼承Adpater
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private SysUserDetailsService sysUserDetailsService;

    @Autowired
    private SiteUserDetailsService siteUserDetailsService;

    // 配置SpringSecurity的過濾器鏈
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 設(shè)置登錄接口放行
        http.authorizeHttpRequests(auth -> auth.requestMatchers("/auth/sys_login","/auth/site_login").permitAll().anyRequest().authenticated());
        // 關(guān)閉csrf
        http.csrf(csrf -> csrf.disable());
        return http.build();
    }


    // 配置AuthenticationManager,配置兩個。一個管理后臺用戶
    @Primary
    @Bean("sysUserAuthenticationManager")
    public AuthenticationManager sysUserAuthenticationManager(PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        // 關(guān)聯(lián)UserDetailsService
        authenticationProvider.setUserDetailsService(sysUserDetailsService);
        // 關(guān)聯(lián)密碼管理器
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(authenticationProvider);
    }


    // 配置AuthenticationManager,管理APP用戶
    @Bean("siteUserAuthenticationManager")
    public AuthenticationManager siteUserAuthenticationManager(PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        // 關(guān)聯(lián)UserDetailsService
        authenticationProvider.setUserDetailsService(siteUserDetailsService);
        // 關(guān)聯(lián)密碼管理器
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(authenticationProvider);
    }

    /**
     * 密碼管理器,會將明文密碼轉(zhuǎn)換成密文,加密,而且不能解碼
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

密碼

需要對數(shù)據(jù)庫中存儲的密碼進行編碼,因為SpringSecurity進行密碼匹配時,會對用戶輸入的密碼先編碼,再驗證,先通過PasswordEncoder生成加密后的密碼

@SpringBootTest
public class MyTestApplication {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Test
    public void test() {
		// 密碼加密
        String encode = passwordEncoder.encode("123456");
        System.out.println(encode);

    }
}

SpringSecurity配置

創(chuàng)建兩個AuthenticationManager,一定要設(shè)置一個主AuthenticationManager否則將會報錯,即在任意一個Bean上添加@Primary注解標(biāo)記

@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;
}

數(shù)據(jù)庫配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springsecurity?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: stt123456

AuthenticationManager

AuthenticationManager用于定義SpringSecurity如何進行身份認(rèn)證,之后將認(rèn)證信息封裝在Authentication對象上,設(shè)置到SecurityContextHolder上,AuthenticationManager常用的實現(xiàn)是ProviderManager,你也可以對其做自定義實現(xiàn)。

到此這篇關(guān)于SpringSecurity多表多端賬戶登錄的實現(xiàn)的文章就介紹到這了,更多相關(guān)SpringSecurity多表多端賬戶登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你怎么解決IDEA中“\t“空格顯示不正確的問題

    教你怎么解決IDEA中“\t“空格顯示不正確的問題

    在之前進行先來先服務(wù)(FCFS)調(diào)度算法的模擬過程中,使用IDEA進行開發(fā)時遇到了"\t"無法補全當(dāng)前字符串長度到8的整數(shù)倍的問題.百度一圈發(fā)現(xiàn)也有很多程序員遇到了這樣的問題,但是沒有解決方法,于是有了這篇文章,需要的朋友可以參考下
    2021-05-05
  • 關(guān)于@Transactional事務(wù)表被鎖的問題及解決

    關(guān)于@Transactional事務(wù)表被鎖的問題及解決

    這篇文章主要介紹了關(guān)于@Transactional事務(wù)表被鎖的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • logback過濾部分日志輸出的操作

    logback過濾部分日志輸出的操作

    這篇文章主要介紹了logback過濾部分日志輸出的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 解決SpringBoot啟動過后不能訪問jsp頁面的問題(超詳細(xì))

    解決SpringBoot啟動過后不能訪問jsp頁面的問題(超詳細(xì))

    這篇文章主要介紹了解決SpringBoot啟動過后不能訪問jsp頁面的問題,文中通過示例代碼介紹的非常詳細(xì),有需要的朋友可以參考一下,希望對你有所幫助。
    2020-05-05
  • Springboot中spring-boot-starter-quartz的使用及說明

    Springboot中spring-boot-starter-quartz的使用及說明

    這篇文章主要介紹了Springboot中spring-boot-starter-quartz的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Java中的Kafka攔截器詳解

    Java中的Kafka攔截器詳解

    這篇文章主要介紹了Java中的Kafka攔截器詳解,Producer?攔截器(interceptor)是在?Kafka?0.10?版本被引入的,主要用于實現(xiàn)?clients?端的定制化控制邏輯,需要的朋友可以參考下
    2023-11-11
  • Java設(shè)計模式之里氏替換原則精解

    Java設(shè)計模式之里氏替換原則精解

    設(shè)計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。本篇介紹設(shè)計模式七大原則之一的里氏替換原則
    2022-02-02
  • 深入分析JAVA 反射和泛型

    深入分析JAVA 反射和泛型

    這篇文章主要介紹了JAVA 反射和泛型的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • 使用springboot整合RateLimiter限流過程

    使用springboot整合RateLimiter限流過程

    這篇文章主要介紹了使用springboot整合RateLimiter限流過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Spring中ClassPath指的是哪些地方

    Spring中ClassPath指的是哪些地方

    在Spring應(yīng)用中,ClassPath指的是應(yīng)用程序的類加載路徑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06

最新評論