RBAC許可權---SpringBoot整合Security

愛叨叨的程式狗發表於2020-12-13

引入SpringSecurity模組

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

加入這個依賴後表示所有的介面都是被保護的狀態,訪問的時候被Security攔截。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-pXAO3H4e-1607867100666)(C:\Users\Liu-PC\Desktop\Security\引入Security1.png)]

在瀏覽器輸入該請求路徑,會自重定向到Spring Security的登入頁。預設的使用者名稱是user,密碼請去IDEA的Consolse去找專案每次啟動時隨機生成的字串:

Using generated security password: 5a38aea2-81d0-485d-bf5c-12c73b0aad27

(複製passwor後的內容即可訪問)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-euN9SLzJ-1607867100668)(C:\Users\Liu-PC\Desktop\Security\Security2.png)]

同時也支援在資料庫配置使用者名稱和密碼(正式專案一般處理方式)或在配置檔案配置使用者名稱密碼,本文使用的是yml配置,properties同理,如果不知道如何配置,請自行百度。配置後在Console中便不自動生成password

spring:
  security:
    user:
      name: Ltx
      password: 123456
      # roles可不配置
      roles: admin

配置HTTP攔截規則

配置介面放行規則

SecurityConfig.class

/**
 * @author Liutx
 * @date 2020/12/13 11:53
 * @Description
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 實際就是為了告訴Spring我的密碼不用加密
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * configure有三個重寫的方法,本方法是基於記憶體的配置使用者角色
     * 在Spring 5.0後需要對密碼進行加密
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("root").password("123456").roles("admin")
                .and()
                .withUser("Ltx").password("123456").roles("user");
    }

    /**
     * 配置HTTP請求規則
     * 什麼請求路徑需要什麼許可權才能訪問,
     * 登入介面,都可訪問
     *
     * @param http
     * @throws Exception
     */
    @Override
     protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(customUrlDecisionManager);
                        object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
                        return object;
                    }
                })
                .and()
                .logout()
                .logoutSuccessHandler((req, resp, authentication) -> {
                            resp.setContentType("application/json;charset=utf-8");
                            PrintWriter out = resp.getWriter();
                            out.write(new ObjectMapper().writeValueAsString(RespBean.ok("登出成功!")));
                            out.flush();
                            out.close();
                        }
                )
                .permitAll()
                .and()
                .csrf().disable().exceptionHandling()
                //沒有認證時,在這裡處理結果,不要重定向
                .authenticationEntryPoint((req, resp, authException) -> {
                            resp.setContentType("application/json;charset=utf-8");
                            resp.setStatus(401);
                            PrintWriter out = resp.getWriter();
                            RespBean respBean = RespBean.error("訪問失敗!");
                            if (authException instanceof InsufficientAuthenticationException) {
                                respBean.setMsg("請求失敗,請聯絡管理員!");
                            }
                            out.write(new ObjectMapper().writeValueAsString(respBean));
                            out.flush();
                            out.close();
                        }
                );
        http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry(), event -> {
            HttpServletResponse resp = event.getResponse();
            resp.setContentType("application/json;charset=utf-8");
            resp.setStatus(401);
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(RespBean.error("您已在另一臺裝置登入,本次登入已下線!")));
            out.flush();
            out.close();
        }), ConcurrentSessionFilter.class);
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
使用postman測試,所以關閉CSRF攻擊,正式環境請開啟
記得要刪掉super.configure(http);  不然會報錯IllegalStateException: Can't configure anyRequest after itself
ObjectMapper類是Jackson庫的主要類。它提供一些功能將轉換成Java物件匹配JSON結構,反之亦然。它使用JsonParser和JsonGenerator的例項實現JSON實際的讀/寫。

表單登入測試

在這裡插入圖片描述

使用post請求構造表單登入,SpringSecurity已做密碼脫敏,許可權中預設使用"ROLE_"為字首。

表單登出測試

在這裡插入圖片描述

登出配置如上程式碼,構造get請求即可。

使用資料庫的方式做登入認證

一、引入資料庫驅動、orm框架(MyBatis-Plus)
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

		<!-- 引入阿里資料庫連線池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>
    
        <!--MyBatis-Plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>8.0.22</version>
        </dependency>

因為敲完這個demo,時間不是很充足,所以沒有更新文章,SpringBoot下與資料庫互動使用許可權認證請去我的github去尋找原始碼,思路根據江南一點雨(鬆哥)的許可權認證思路而來。

專案原始碼Git地址

鬆哥Github地址

相關文章