首頁 > 軟體

一文詳解Spring Security的基本用法

2022-05-19 19:00:10

Spring Security是一個功能強大且高度可客製化的身份驗證和存取控制框架, 提供了完善的認證機制和方法級的授權功能。是一款非常優秀的許可權管理框架。它的核心是一組過濾器鏈,不同的功能經由不同的過濾器。 今天通過一個簡單的案例瞭解一下Spring Security的基本用法

1.引入依賴

在專案中引入Spring Security依賴,程式碼如下:

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

引入依賴後,整個專案都被Spring Security保護起來,所有的介面都要登入之後才能存取了,例如,我需要存取/doc.html介面檔案,直接跳到登入頁面。如下圖:

這時,你會有十萬個為什麼啦?這個頁面哪裡的?這個使用者名稱和密碼是啥?等等。不著急,聽我一一道來。

2.使用者名稱和密碼在哪裡設定

當我們引入了Spring Secruity依賴後,啟動專案之後,密碼就會在控制檯中輸出的,格式是UUID,每一次啟動密碼都不一樣的,而使用者名稱是預設是User的。

Using generated security password: 8b2d752b-8892-4cd3-a7a9-a36e79e1cad8

我們可以通過專案的組態檔自定義使用者名稱和密碼的,程式碼如下,這樣每次重啟專案,使用者名稱和密碼都是固定不變的。

spring:
  security:
      user:
        name: didiplus
        password: didiplus

3.UserDetailsService介面詳解

UserDetailsService介面只有一個抽象方法就是loadUserByUsername(String username)。程式碼如下:

public interface UserDetailsService {

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

}

UserDetailsService介面的返回值是UserDetails介面, 這又是一個介面,Spring Security框架提供了它的實現類org.springframework.security.core.userdetails包下的User類物件 。userdetails原始碼如下:

Spring Security提供了三個UserDetailsService介面的實現類,分別是CachingUserDetailsServiceJdbcDaoImplInMemoryUserDetailsManager

3.1JdbcDaoImpl實現類

該實現類是通過資料庫獲取使用者名稱和密碼,JdbcUserDetailsManager中定義了一大堆SQL語句,如下:

接著我們在看一下JdbcDaoImpl中的loadUsersByUsername方法,如下:

3.2InMemoryUserDetailsManager實現類

以上程式碼是判斷記憶體中的HashMap集合中是否有使用者資料對應的User物件,如果沒有,直接丟擲異常,如果有就返回該使用者的User物件資訊。

以上程式碼是把組態檔中的User相關資訊讀取到。通過分析原始碼發現 Spring Security框架完成使用者登入認證的核心就在與org.springframework.security.core.userdetails包下的UserDetailsService介面。

3.3自定義實現類實現UserDetailsService介面

自定義實現類MyUserDetailsServiceImpl,程式碼如下:

@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {

    private static  final  String USERNAME="admin";
    private static  final  String PASSWORD="admin123";

 

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (!USERNAME.equals(username)){
            throw new UsernameNotFoundException("使用者名稱不存在");
        }
        UserDetails userDetails =  new User(USERNAME,PASSWORD, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));
        return userDetails;
    }
}

重啟專案看看,輸入定義的使用者名稱和密碼,發現登入不了,檢視控制檯發現報錯,提示如下:

報錯的原因是沒有使用任何的PasswordEncoder,我們輸入的密碼沒有用加密工具進行加密 。 Spring Security其實已經給我們提供了很多的PasswordEncoder 。 在org.springframework.security.crypto.password包下有一個PasswordEncoder介面,看看他的實現類

把這個PasswordEncoder的任意一個我們需要用來加密密碼的實現類的Bean注入到容器裡面,就可以直接拿來使用 ,程式碼如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

修改MyUserDetailsServiceImpl類如下:

@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {

    private static  final  String USERNAME="admin";
    private static  final  String PASSWORD="admin123";

    @Resource
    BCryptPasswordEncoder cryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (!USERNAME.equals(username)){
            throw new UsernameNotFoundException("使用者名稱不存在");
        }
        UserDetails userDetails =  new User(USERNAME,cryptPasswordEncoder.encode(PASSWORD), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));
        return userDetails;
    }
}

重啟專案再次測試,輸入定義的賬號和密碼。即可存取到介面檔案頁面。

4.如何修改登入頁面

覺得預設的登入頁面很醜,我們如何定義自己的登入頁面呢?方法也很簡單,首先我們先去準備一個登入頁面。如下:

前端程式碼如下:

<form action="/login" class="login-form" >
    <h1>登入</h1>

    <div class="txtb">
        <input type="text" name="user">
        <span data-placeholder="Username"></span>
    </div>

    <div class="txtb">
        <input type="password" name="pass">
        <span data-placeholder="Password"></span>
    </div>
    <input type="submit" class="logbtn" value="登入">

    <div class="bottom-text">
        Don't have account? <a href="#" rel="external nofollow" >Sign up</a>
    </div>

</form>

把登入頁面檔案存放到專案的資原始檔夾中static目錄下,然後在SecurityConfig重寫configure(HttpSecurity http)這個方法,程式碼如下:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login.html") #自定義登入頁面
                .usernameParameter("user") #對應前端表達name屬性
                .passwordParameter("pass") #對應前端表達name屬性
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/doc.html") #登入成功後跳轉的頁面地址
                .failureUrl("/login?error=true")
                .and()
                .authorizeRequests()
                .antMatchers("/login.html").permitAll() #放通登入頁面
                .anyRequest().authenticated(); #其他請求都要認證
        http.csrf().disable();
    }

重新啟動專案,輸入定義的使用者名稱和密碼,登入成功直接跳轉到/doc.html

antMatchers("url").permitAll() 是把某個url放通,不需要登入就能存取。

到此這篇關於一文詳解Spring Security的基本用法的文章就介紹到這了,更多相關Spring Security用法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com