[Spring Cloud] - Spring Security實踐(一)- 基本概念及實踐

基本使用

Spring security須要的基本依賴:web

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

其餘部分不須要任何的增長。spring

Security的理論是兩個核心:認證(我是誰)和鑑權(我能作什麼)。
在code中,這兩個核心都須要經過繼承WebSecurityConfigurerAdapter來實現。app

➡️廢話很少說,上代碼ide

首先,確保yml中添加了上面提到的兩個依賴。添加後這就是最基本的spring security工程了。spring-boot

而後,咱們能夠先添加一些controller。好比IndexControlleroop

@RestController
public class IndexController{
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(){
        return "index";
    }
}

此時啓動項目,會發現啓動log中夾雜着一句亂碼:ui

Using generated security password: 2465a939-a37d-4d3e-9ee1-05d2e51f18fb

這個「亂碼」就是spring security提供的缺省密碼。
此時訪問項目url,會自動跳轉到項目url/login頁面。
image.png
默認username爲user, password欄輸入剛剛那一句「亂碼」。
點擊signin,發現跳轉成功,會訪問到咱們最初訪問的頁面。加密

自定義用戶名密碼 - 第一種內存模式

建立@configuration: url

新建一個類,繼承 WebSecurityConfigurerAdapter, 添加註解@EnableWebSecurity (不用再添加@Configuration註解,由於已被EnableWebSecurity包含)以下所示。spa

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}

覆寫父類方法:

覆寫configure(AuthenticationManagerBuilder auth)方法
⚠️ 父類中包含多個configure方法,注意選擇正確方法。代碼以下所示:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER");
}

此方法實現了三個功能:

  1. 定義了用戶名和密碼(user/123)
  2. 加密了密碼 - ⚠️ springsecurity強制密碼加密,此處必須這樣寫
  3. 定義此用戶的role爲USER - Spring security根據role來作鑑權操做,此處只是認證,暫時忽視便可。

此時,重啓項目,已經看不到最開始那一串亂碼了,使用user/123登錄,便可跳轉至正確頁面。

自定義用戶名密碼 - 第二種內存模式

**此處注意,security 5.0以後的版本,須要在密碼前加上加密格式。
因此僅僅使用BCryptPasswordEncoder將密碼encode還不夠,還要在encode後的密碼前方加上密碼格式。**

官方說明:

The general format for a password is:
 
{id}encodedPassword
Such that id is an identifier used to look up which PasswordEncoder should be used and encodedPassword is the original encoded password for the selected PasswordEncoder. The id must be at the beginning of the password, start with { and end with }. If the id cannot be found, the id will be null. For example, the following might be a list of passwords encoded using different id. All of the original passwords are "password".
 
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG 
{noop}password 
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc 
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=  
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
@Configuration
public class AuthConfiguration {
 @Bean
 public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        String password = new BCryptPasswordEncoder().encode("123");

// 正確的結果
manager.createUser(User.withUsername("user").password("{bcrypt}" + password).roles("USER").build());
       
// 錯誤  
manager.createUser(User.withUsername("admin").password(password).roles("ADMIN").build());
// 錯誤     
manager.createUser(User.withUsername("all").password(password).roles("USER", "ADMIN").build());
        return manager;
    }
}

鑑權

覆寫方法
鑑權依靠的是另外一個方法: configure(HttpSecurity http),注意:其中httpSecurity表明一整套過濾器鏈,每一個過濾器表示一個配置項。
代碼以下:

@Override
    protected void configure(HttpSecurity http) throws Exception {
    }

示例代碼及註釋以下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
         // 匹配 "/","/index" 路徑,不須要權限便可訪問
        .antMatchers("/user/user1").permitAll()
         // 匹配 "/admin" 及其如下全部路徑,都須要 "USER" 權限
        .antMatchers("/admin/**").hasRole("USER")
        .and()
        // 登陸地址爲 "/login",登陸成功默認跳轉到頁面 "/user"
        .formLogin().loginPage("/login").defaultSuccessUrl("/user/user1")
        .and()
        // 退出登陸的地址爲 "/logout",退出成功後跳轉到頁面 "/login"
        .logout().logoutUrl("/logout").logoutSuccessUrl("/login");
}
相關文章
相關標籤/搜索