(一)創建簡單的Spring security 項目

參考:陳木鑫老師的《Spring Security 實戰》

創建spring boot項目

通過Intellij IDEA創建Spring Boot項目的方式有許多種,其中最簡單的方式就是使用Spring Initializr
工具。
Spring Initializr 允許我們提前選定一些常用的項目依賴,此處我們選擇 Security 作爲構建Spring
Security項目的最小依賴,選擇Web作爲Spring Boot構建Web應用的核心依賴。
在這裏插入圖片描述
Next :
在這裏插入圖片描述
Next:
在這裏插入圖片描述
創建項目的目錄結構:
在這裏插入圖片描述

maven 引用

在自動構建的Spring Security 項目中,Spring Initializr 爲我們引入了以下依賴:

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

我們點開spring-boot-starter-security可以看到,其包含了以下依賴:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.3.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <scope>compile</scope>
    </dependency>

其中 spring-security-webspring-security-config兩個核心模塊,正是官方建議引入的Spring Security最小依賴。

聲明controller

在項目中聲明一個測試路由TestController

package com.haan.springsecuritydemo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping
    public String hello(){
        return "Hello Spring Security!";
    }
}

在這裏插入圖片描述

運行SpringsecuritydemoApplication

運行SpringsecuritydemoApplication,默認啓動 8080 端口,打開瀏覽器,訪問localhost:8080,我們發現頁面跳轉到了localhost:8080/login:
在這裏插入圖片描述
在引入Spring Security項目之後,雖然沒有進行任何相關的配置或編碼,但Spring Security有一個默認的運行狀態,要求在經過表單基本認證後才能訪問對應的URL資源,其默認使用的用戶名爲 user ,密碼則是動態生成並打印到控制檯的一串隨機碼。翻看控制檯的打印信息:
在這裏插入圖片描述
輸入用戶名和密碼後,單擊“登錄”按鈕即可成功訪問:
在這裏插入圖片描述

修改登錄信息

基本表單認證中,用戶名和密碼都是可以配置的,最常見的就是在resources下的application配置文件中修改:

spring.security.user.name=user02
spring.security.user.password=aaaaaa

重新啓動程序,發現控制檯不再打印默認密碼串了,此時使用我們自定義的用戶名和密碼即可登錄。

WebSecurityConfigurerAdapter

    protected void configure(HttpSecurity http) throws Exception {
        this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
        ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated().and()).formLogin().and()).httpBasic();
    }

可以看到 WebSecurityConfigurerAdapter 已經默認聲明瞭一些安全特性:

  • 驗證所有請求。
  • 允許用戶使用表單登錄進行身份驗證(Spring Security 提供了一個簡單的表單登錄頁面)。
  • 允許用戶使用HTTP 基本認證。

spring boot 默認定義了DefaultConfigurerAdapter ,由@ConditionalOnMissingBean可知當沒有其他WebSecurityConfigurerAdapter被定義時,將使用DefaultConfigurerAdapter

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({WebSecurityConfigurerAdapter.class})
@ConditionalOnMissingBean({WebSecurityConfigurerAdapter.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
public class SpringBootWebSecurityConfiguration {
    public SpringBootWebSecurityConfiguration() {
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @Order(2147483642)
    static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
        DefaultConfigurerAdapter() {
        }
    }
}

自定義表單登錄頁

Spring boot提供了WebSecurityConfigurerAdapter 的默認實現DefaultConfigurerAdapter,能夠提供基本表單登錄認證。

雖然自動生成的表單登錄頁可以方便、快速地啓動,但是大多數應用程序更希望提供自己的表單登錄頁,此時就需要我們提供自己的WebSecurityConfigurerAdapter來代替DefaultConfigurerAdapter,覆寫WebSecurityConfigurerAdapterconfigure方法:

@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/myLogin.html")	//指明登錄頁面
                .permitAll()    //指明登錄頁允許所有進行訪問
                .and()
                .csrf().disable();
    }
}
  • authorizeRequests()方法實際上返回了一個 URL 攔截註冊器,我們可以調用它提供的anyRequest()antMatchers()regexMatchers()等方法來匹配系統的URL,併爲其指定安全策略。
  • formLogin()方法和httpBasic()方法都聲明瞭需要Spring Security提供的表單認證方式,分別返回對應的配置器。其中formLogin().loginPage("/myLogin.html")指定自定義的登錄
    /myLogin.html,同時,Spring Security會用/myLogin.html註冊一個POST路由,用於接收登錄請求。
  • csrf()方法是Spring Security提供的跨站請求僞造防護功能,當我們繼承WebSecurityConfigurer Adapter時會默認開啓 csrf()方法。

訪問localhost:8080 ,我們發現,頁面就跳轉到了localhost:8080/myLogin.html,由於我們靜態文件中並沒有myLogin.html 文件,所以提示了一個404的white page:
在這裏插入圖片描述
我們在resources/static 文件夾下創建頁面myLogin.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello Security!</title>
</head>
<body>
    <h3>登錄頁</h3>
    <form action="/myLogin.html" method="post">
        <input type="text" name="username"> <br/>
        <input type="text" name="password"> <br/>
        <input type="submit" value="login">
    </form>
</body>
</html>

重啓服務,再次訪問localhost:8080:
在這裏插入圖片描述
輸入上面的application.properties中配置的用戶登錄賬戶和密碼進行登錄,登陸成功:
在這裏插入圖片描述

其他表單配置項

指定登錄處理URL

在自定義表單登錄頁之後,處理登錄請求的URL也會相應改變,默認情況下,
如果只配置loginPage而不配置loginProcessingUrl的話那麼loginProcessingUrl默認就是loginPage,如果需要自定義登錄請求的URL,需要配置loginProcessingUrl:


重啓登錄,我們發現中間訪問了localhost:8080/myLogin
在這裏插入圖片描述

補充:loginPageloginProcessingUrl

  • 兩者都不配置:默認都是/login
  • 兩者都配置:按自己的來
  • 只配置loginProcessingUrlloginPage默認/login
  • 只配置loginPage: loginProcessingUrl默認就是loginPage

設置登錄成功處理

此時,有些讀者可能會有疑問,因爲按照慣例,在發送登錄請求並認證成功之後,頁面會跳轉回原訪問頁。在某些系統中的確是跳轉回原訪問頁的,但在部分前後端完全分離、僅靠JSON完成所有交互的系統中,一般會在登錄時返回一段 JSON 數據,告知前端成功登錄成功與否,由前端決定如何處
理後續邏輯,而非由服務器主動執行頁面跳轉。這在Spring Security中同樣可以實現。

表單登錄配置模塊提供了successHandler()failureHandler()兩個方法,分別處理登錄成功和登錄失敗的邏輯。

  • successHandler()方法帶有一個Authentication參數,攜帶當前登錄用戶名及其角色等信息;

  • failureHandler()方法攜帶一個AuthenticationException異常參數。具體處理方式需按照系統的情況自定義。

@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/myLogin.html") //指明登錄頁面
                .loginProcessingUrl("/myLogin")   //指明處理登陸的URL路徑,即登陸表單提交請求
                .successHandler(new AuthenticationSuccessHandler() {        // 設置登錄成功的處理器
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        PrintWriter responseWriter = httpServletResponse.getWriter();
                        String name = authentication.getName();
                        responseWriter.write(name+" login success!");
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {        // 設置登錄失敗的處理器
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        PrintWriter responseWriter = httpServletResponse.getWriter();
                        responseWriter.write("login error!");
                    }
                })
                .permitAll()    //指明登錄頁允許所有進行訪問
                .and()
                .csrf().disable();
    }
}

正確的賬號密碼:
在這裏插入圖片描述
錯誤的賬號密碼:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章