最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Security+MyBatis實(shí)現(xiàn)從數(shù)據(jù)庫(kù)動(dòng)態(tài)查詢權(quán)限的完整實(shí)現(xiàn)方案

 更新時(shí)間:2026年04月12日 15:09:00   投稿:bairu  
文章詳細(xì)介紹了SpringSecurity從數(shù)據(jù)庫(kù)動(dòng)態(tài)查詢權(quán)限的實(shí)現(xiàn)方案,包括核心接口、數(shù)據(jù)庫(kù)表設(shè)計(jì)、MyBatis查詢權(quán)限、UserDetailsService實(shí)現(xiàn)、SpringSecurity配置、Controller使用及常見(jiàn)問(wèn)題優(yōu)化等內(nèi)容,該方案生產(chǎn)可用,靈活且遵循SpringSecurity接口設(shè)計(jì)標(biāo)準(zhǔn)

一、整體思路

Spring Security 的核心接口:

  • UserDetailsService:根據(jù)用戶名加載用戶信息(密碼、權(quán)限等)
  • UserDetails:用戶對(duì)象,包含密碼和 GrantedAuthority
  • GrantedAuthority:權(quán)限標(biāo)識(shí)(如 ROLE_ADMIN 或 system:user:delete

流程
登錄 → UserDetailsService.loadUserByUsername() → 查數(shù)據(jù)庫(kù) → 返回 UserDetails → Security自動(dòng)比對(duì)密碼 → 把權(quán)限存入SecurityContext。

二、數(shù)據(jù)庫(kù)表設(shè)計(jì)(最簡(jiǎn)但完整)

-- 用戶表
CREATE TABLE `user` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(255) NOT NULL,   -- BCrypt加密
  `enabled` tinyint DEFAULT 1
);
-- 角色表
CREATE TABLE `role` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `role_code` varchar(50) NOT NULL   -- ROLE_ADMIN, ROLE_USER
);
-- 權(quán)限表(細(xì)粒度權(quán)限)
CREATE TABLE `permission` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `perm_code` varchar(100) NOT NULL  -- user:add, user:delete, order:view
);
-- 用戶-角色關(guān)聯(lián)
CREATE TABLE `user_role` (
  `user_id` int,
  `role_id` int
);
-- 角色-權(quán)限關(guān)聯(lián)
CREATE TABLE `role_permission` (
  `role_id` int,
  `perm_id` int
);

示例數(shù)據(jù):

-- 用戶 admin / 123456(實(shí)際用BCrypt)
INSERT INTO `user` VALUES (1, 'admin', '$2a$10$NkMwpJ7UoWjQlqWjQlqWjQ', 1);
-- 角色
INSERT INTO `role` VALUES (1, 'ROLE_ADMIN'), (2, 'ROLE_USER');
-- 權(quán)限
INSERT INTO `permission` VALUES (1, 'user:list'), (2, 'user:delete');
-- 管理員擁有所有角色和權(quán)限
INSERT INTO `user_role` VALUES (1,1);
INSERT INTO `role_permission` VALUES (1,1),(1,2);

三、MyBatis 查詢權(quán)限

1. 實(shí)體類

public class User {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    // getter/setter
}

2. Mapper 接口

@Mapper
public interface UserMapper {
    @Select("SELECT id, username, password, enabled FROM user WHERE username = #{username}")
    User findByUsername(String username);
    @Select("SELECT r.role_code FROM user_role ur " +
            "JOIN role r ON ur.role_id = r.id " +
            "WHERE ur.user_id = #{userId}")
    List<String> findRolesByUserId(Integer userId);
    @Select("SELECT p.perm_code FROM user_role ur " +
            "JOIN role_permission rp ON ur.role_id = rp.role_id " +
            "JOIN permission p ON rp.perm_id = p.id " +
            "WHERE ur.user_id = #{userId}")
    List<String> findPermissionsByUserId(Integer userId);
}

四、核心:實(shí)現(xiàn) UserDetailsService

@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1. 查用戶
        User user = userMapper.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用戶不存在: " + username);
        }
        // 2. 查角色(ROLE_xxx)
        List<String> roles = userMapper.findRolesByUserId(user.getId());
        // 3. 查權(quán)限(user:add 等)
        List<String> permissions = userMapper.findPermissionsByUserId(user.getId());
        // 4. 合并權(quán)限 + 角色
        //    注意:Spring Security 中角色需要加 ROLE_ 前綴
        Set<GrantedAuthority> authorities = new HashSet<>();
        for (String role : roles) {
            // 如果role已經(jīng)是 ROLE_ADMIN 格式,直接加;否則自動(dòng)補(bǔ)
            if (role.startsWith("ROLE_")) {
                authorities.add(new SimpleGrantedAuthority(role));
            } else {
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
            }
        }
        for (String perm : permissions) {
            authorities.add(new SimpleGrantedAuthority(perm));
        }
        // 5. 返回 UserDetails
        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            user.getEnabled(),      // 是否啟用
            true,                   // 賬號(hào)未過(guò)期
            true,                   // 憑證未過(guò)期
            true,                   // 賬號(hào)未鎖定
            authorities
        );
    }
}

五、Spring Security 配置類

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();  // 密碼加密
    }
    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                   .authenticationProvider(provider)
                   .build();
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // 公開(kāi)接口
                .requestMatchers("/login", "/register").permitAll()
                // 權(quán)限控制:需要具體權(quán)限
                .requestMatchers("/user/list").hasAuthority("user:list")
                .requestMatchers("/user/delete").hasAuthority("user:delete")
                // 角色控制
                .requestMatchers("/admin/**").hasRole("ADMIN")
                // 其他請(qǐng)求需要認(rèn)證
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .permitAll()
            )
            .logout(LogoutConfigurer::permitAll)
            .csrf(csrf -> csrf.disable());  // 根據(jù)實(shí)際情況開(kāi)啟
        return http.build();
    }
}

六、在 Controller 中使用

@RestController
public class UserController {
    @GetMapping("/user/list")
    public String listUsers() {
        return "用戶列表(需要 user:list 權(quán)限)";
    }
    @GetMapping("/user/delete")
    public String deleteUser() {
        return "刪除用戶(需要 user:delete 權(quán)限)";
    }
    @GetMapping("/current-permissions")
    public Authentication getCurrentAuth() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

七、常見(jiàn)問(wèn)題與優(yōu)化

1. 緩存權(quán)限查詢

不要在每次請(qǐng)求時(shí)重復(fù)查數(shù)據(jù)庫(kù)(Security 本身一次登錄后權(quán)限存session)。

如果一定要?jiǎng)討B(tài)刷新權(quán)限,可以:

// 修改權(quán)限后,重新加載
SecurityContextHolder.getContext().setAuthentication(updatedAuth);

2. 使用 @PreAuthorize 更優(yōu)雅

@PreAuthorize("hasAuthority('user:delete')")
@DeleteMapping("/user/{id}")
public String delete(@PathVariable Long id) {
    return "刪除成功";
}

需要開(kāi)啟:

@EnableGlobalMethodSecurity(prePostEnabled = true)

3. 性能優(yōu)化:一次查詢返回用戶+角色+權(quán)限

用 MyBatis 聯(lián)表或 ResultMap 一次性查出來(lái),避免 N+1 問(wèn)題。

<resultMap id="UserWithAuth" type="com.example.User">
    <id column="id" property="id"/>
    <collection property="roles" ofType="string" select="..."/>
</resultMap>

八、總結(jié):這套方案的特點(diǎn)

方面說(shuō)明
? 生產(chǎn)可用絕大多數(shù)項(xiàng)目真實(shí)采用
? 靈活權(quán)限可存數(shù)據(jù)庫(kù),隨時(shí)調(diào)整
? 標(biāo)準(zhǔn)完全遵循 Spring Security 接口設(shè)計(jì)
?? 注意密碼必須用 BCrypt 等單向加密
?? 注意角色必須加 ROLE_ 前綴(除非自定義)

以上就是Spring Security+MyBatis實(shí)現(xiàn)從數(shù)據(jù)庫(kù)動(dòng)態(tài)查詢權(quán)限的完整實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于Spring Security MyBatis數(shù)據(jù)庫(kù)動(dòng)態(tài)查詢權(quán)限的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java程序的邏輯控制和方法詳解

    Java程序的邏輯控制和方法詳解

    這篇文章主要介紹了Java程序的邏輯控制和方法詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • String.intern()作用與常量池關(guān)系示例解析

    String.intern()作用與常量池關(guān)系示例解析

    這篇文章主要為大家介紹了String.intern()作用與常量池關(guān)系示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 在 Spring Boot 中實(shí)現(xiàn)異常處理最佳實(shí)踐

    在 Spring Boot 中實(shí)現(xiàn)異常處理最佳實(shí)踐

    本文介紹如何在Spring Boot中實(shí)現(xiàn)異常處理,涵蓋核心概念、實(shí)現(xiàn)方法、與先前查詢的集成、性能分析、常見(jiàn)問(wèn)題和最佳實(shí)踐,感興趣的朋友一起看看吧
    2025-04-04
  • Spring Bean創(chuàng)建和循環(huán)依賴

    Spring Bean創(chuàng)建和循環(huán)依賴

    這篇文章主要介紹了Spring Bean創(chuàng)建和循環(huán)依賴,講述了Spring容器中?Bean?的創(chuàng)建過(guò)程已經(jīng)主要的方法,另外也著重分析了循環(huán)依賴的問(wèn)題,需要的小伙伴可以參考一下
    2022-05-05
  • Java transient關(guān)鍵字與序列化操作實(shí)例詳解

    Java transient關(guān)鍵字與序列化操作實(shí)例詳解

    這篇文章主要介紹了Java transient關(guān)鍵字與序列化操作,結(jié)合實(shí)例形式詳細(xì)分析了java序列化操作相關(guān)實(shí)現(xiàn)方法與操作注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理

    Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理

    MyBatis是一種流行的Java持久化框架,它提供了靈活而強(qiáng)大的查詢映射功能,本文主要介紹了Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • 百度Java面試題 前200頁(yè)精選(中)

    百度Java面試題 前200頁(yè)精選(中)

    這篇文章主要為大家分享了Java面試資源中篇,百度“Java面試題”前200頁(yè)都在這里了,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • SpringCloud Feign的使用代碼實(shí)例

    SpringCloud Feign的使用代碼實(shí)例

    這篇文章主要介紹了SpringCloud Feign的使用代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 解決Java的InputMismatchException異常

    解決Java的InputMismatchException異常

    這篇文章介紹了解決Java的InputMismatchException異常的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • java 實(shí)現(xiàn)計(jì)數(shù)排序和桶排序?qū)嵗a

    java 實(shí)現(xiàn)計(jì)數(shù)排序和桶排序?qū)嵗a

    這篇文章主要介紹了java 實(shí)現(xiàn)計(jì)數(shù)排序和桶排序?qū)嵗a的相關(guān)資料,需要的朋友可以參考下
    2017-02-02

最新評(píng)論

铅山县| 景德镇市| 项城市| 泗阳县| 夏河县| 青铜峡市| 章丘市| 岳阳市| 古蔺县| 雅江县| 太白县| 石屏县| 鲁甸县| 甘洛县| 云梦县| 洛阳市| 麻江县| 驻马店市| 邓州市| 武冈市| 永福县| 莱州市| 额济纳旗| 北京市| 盐亭县| 蛟河市| 阿鲁科尔沁旗| 佛坪县| 江西省| 灵武市| 大余县| 乳源| 增城市| 土默特左旗| 锡林浩特市| 岢岚县| 吉隆县| 阿拉善盟| 田东县| 西藏| 临泉县|