第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Spring Security Spring Security Spring Security 用戶名密碼認證

Spring Security 用戶名密碼認證實例

1. 前言

上一節(jié),我們介紹了 Spring Security 的基本認證組件,本節(jié)我們介紹最常見的認證方式「密碼認證」的實現(xiàn)方法。

用戶名、密碼認證被廣泛應用于 PC 端的 Web 應用和客戶端應用,比如登陸網站,又比如 QQ 桌面客戶端。

圖片描述

圖 1 慕課登錄頁面
Spring Security 提供了成熟的用戶名密碼認證解決方案。 針對用戶名、密碼認證,從認證請求方式的角度,可以將認證過程分為三類:
  1. 表單登錄;
  2. 基本認證;
  3. 數字認證。

從認證數據源角度分類,也可以將認證分為:

  1. 使用內存存儲;
  2. 使用關系型數據庫存儲;
  3. 自定義存儲;
  4. LDAP 存儲。

本小節(jié)實例開發(fā)環(huán)境

本小節(jié)所使用的實例代碼是基于 Spring 官網中提供的最小化 HelloWorld 模板創(chuàng)建,請點此下載完整的 HelloWorld 模板壓縮包

  • 編譯環(huán)境:JDK 1.8,點此下載;

  • 構建工具:Maven 3.5.3,點此下載;

  • 開發(fā)工具:VS Code,點此下載、控制臺;

  • 其他依賴性:無

2. 實例講解

2.1 創(chuàng)建 Spring Security 項目

  1. 修改 Hello World 模板工程的目錄名稱為 UsernamePasswordSample;
  2. 修改 pom.xml 文件,將基礎信息部分改為如下形式:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
略...
	<groupId>imooc.springsecurity</groupId>
	<artifactId>UsernamePasswordSample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
略...
</project>
  1. 修改啟動類,修改其包名為 imooc.springsecurity.usernamepassword,修改類名為 UsernamePasswordSample;

  2. 創(chuàng)建測試頁面,返回登錄用戶信息

新建 src/main/java/imooc/springsecurity/usernamepassword/controller/UserController.java。

package imooc.springsecurity.usernamepassword.controller;

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

import java.security.Principal;

@RestController
@RequestMapping("user")
public class UserController {
    @RequestMapping("me")
    private String showMe(Principal principal) {
        return String.format("當前登錄用戶為:「%s」", principal.getName());
    }
}
  1. 在項目根目錄控制臺輸入命令 mvn spring-boot:run,如看到以下輸出代表配置正確。

圖片描述

2.2 表單認證

2.2.1 表單認證的過程說明

Spring Security 支持從 HTML 的 Form 表單形式提交登錄用戶信息。

表單認證可分為以下步驟:

  1. 用戶請求受保護資源;
  2. Spring Security 的 FilterSecurityInterceptor 對象,檢測到當前用戶認證未通過,應予以拒絕,并拋出 AccessDeniedException;
  3. AccessDeniedExceptionExceptionTranslationFilter 接收后,其認定需要發(fā)起認證流程,此時用戶被要求登錄,認證服務器將登錄地址(默認由 LoginUrlAuthenticationEntryPoint)返回給客戶端;
  4. 客戶端瀏覽重定向到登錄頁面;
  5. 登錄頁面有服務端渲染生成。

圖片描述

圖 2 表單登錄流程

當用戶提交登錄信息,認證服務器端的 UsernamePasswordAuthenticationFilter 就會被執(zhí)行。

此過程的具體執(zhí)行過程如下:

  1. UsernamePasswordAuthenticationFilter 產生 UsernamePasswordAuthenticationToken,并存入從請求中獲取的用戶名、密碼等信息;
  2. 創(chuàng)建出的 Token 被傳遞給 AuthenticationManager 用于認證;
  3. 認證成功或失敗的后續(xù)流程同上一小節(jié)中關于 AbstractAuthenticationProcessingFilter 的執(zhí)行過程一致。

2.2.2 表單認證的開啟

默認情況下,Spring Security 開啟了表單認證功能。如果我們需要顯式配置,可用如下方式實現(xiàn)。

創(chuàng)建 Security 配置文件: src/main/java/imooc/springsecurity/usernamepassword/config/WebSecurityConfig.java,并在其中添加 http.formLogin(withDefaults()) 的配置,完整代碼如下:

package imooc.springsecurity.usernamepassword.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin(Customizer.withDefaults());
    }

}

訪問 http://localhost:8080/user/me ,網頁會自動跳轉到登錄頁面。

圖片描述

登錄頁面
輸入默認生成的用戶名 「user」, 默認生成密碼可在控制臺日志中找到。如下圖:

圖片描述

提交登錄后,通過認證,我們將在瀏覽器看到當前登錄的用戶名。

當前登錄用戶為:「user」

2.2.3 表單認證的配置

默認情況下,表單登錄的跳轉地址是 /login,登錄參數中用戶名變量名為 username,密碼變量名為 password。如果我們需要修改這些配置信息,可以通過如下方式實現(xiàn):

configure(HttpSecurity http) 方法中,為 httpformLogin 項修改配置。

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll() // 表單認證頁面不需要權限
                .anyRequest().authenticated(); // 其他頁面需要登錄用戶才能訪問

        http.formLogin()
                .loginPage("/login") // 自定義表單認證頁面地址
                .usernameParameter("user")
                .passwordParameter("pass");

        http.csrf().disable(); // 關閉 csrf 以通過認證,注意,這不是最好的做法,后續(xù)章節(jié)會有介紹。
    }

當然這一步中配置 /login 頁面需要我們自己去實現(xiàn)。這里有幾個需要注意的地方:

  1. 自定義表單提交地址為 /login ,提交方法僅支持 POST;
  2. 表單需要支持 CSRF 票據,即附帶 _csrf 參數;
  3. 用戶名字段需要命名為 user;
  4. 密碼字段需要命名為 pass;
  5. 當認證失敗時,表單頁面會收到 error 參數;
  6. 當用戶退出成功時,表單頁面會收到 logout 參數。

為了測試上述配置,我們創(chuàng)建一個測試登錄頁:

  1. 新建 src/main/java/imooc/springsecurity/usernamepassword/controller/LoginController.java。
package imooc.springsecurity.usernamepassword.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String viewLogin2() {
        return "/login.html";
    }
}
  1. 新建 src/main/resources/templates/login.html
<form method="post" action="/login">
    <input type="text" name="user">
    <input type="password" name="pass">
    <input type="submit" value="登錄">
</form>

訪問測試:http://localhost:8080/user/me ,此時跳轉到我們新建的登錄頁面。

圖片描述

登錄頁面
輸入用戶名密碼后可看到用戶信息。

2.3 基本認證

2.3.1 基本認證的流程

基本認證也是常用的認證方式?;菊J證分兩種場景:

  1. 如果直接在瀏覽器里訪問頁面,瀏覽器會彈出登錄窗口,如下圖:
  2. 如果發(fā)送未經認證的 http 請求,服務端會返回 401 錯誤。

實現(xiàn)基本認證有兩種方式:

  1. 在請求頭中添加 Authorization: "Basic Base64(用戶名+密碼)";
  2. 在請求參數中增加用戶名和密碼。

在 Spring Security 中,具體的認證過程如下:

  1. 用戶請求受保護資源;(與表單認證相同)
  2. Spring Security 的 FilterSecurityInterceptor 對象,檢測到當前用戶認證未通過,應予以拒絕,并拋出 AccessDeniedException;(與表單認證相同)
  3. AccessDeniedExceptionExceptionTranslationFilter 接收后,其認定需要發(fā)起認證流程,此時用戶被要求登錄,認證服務器將認證頭 WWW-Authenticate (默認由 BasicAuthenticationEntryPoint 提供)返回給客戶端。

當客戶端收到 WWW-Authenticate 頭后,客戶端提供用戶名和密碼參數用于認證。

2.3.2 基本認證的配置

默認情況下,Spring Security 開啟了基本認證功能。如果我們需要顯式配置,可用如下方式實現(xiàn)。

protected void configure(HttpSecurity http) {
    http
        // ...
        .httpBasic(withDefaults());
}

2.4 數字認證

數字認證在新型應用中已不建議使用,因為這種方式下,用戶的敏感信息,比如密碼等都需要以明文形式存在,因此數字認證方式并不安全。

數字認證對應的認證過濾器為:DigestAuthenticationFilter。

2.5 在內存中配置用戶名密碼

內存認證是將用戶名密碼信息存儲在內存之中,通過 InMemoryUserDetailsManager 方式完成認證。

內存認證添加用戶的方式如下,在 WebSecurityConfig.java 類(非必須)中添加以下 Bean 定義。

@Bean
public UserDetailsService users() {
  	// 用戶1 user 用戶
    UserDetails user = User.builder()
        .username("user")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER")
        .build();

    // 用戶2 admin 用戶
    UserDetails admin = User.builder()
        .username("admin")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER", "ADMIN")
        .build();

    return new InMemoryUserDetailsManager(user, admin);
}

注意,其中的密碼字段需要符合系統(tǒng)加密規(guī)則。比較簡單的生成方式是通過 Spring Boot CLI 工具,在控制臺將密碼轉換為密文。

然后我們可以在登錄表單中,用這里配置的用戶信息完成認證。

2.6 使用數據庫管理用戶名密碼

Spring Security 支持使用數據庫作為認證數據源,并且提供了默認數據模型。

2.6.1 默認的數據模型

使用 JDBC 數據源最簡單直接的方法就是使用 Spring Security 提供的默認數據模型「users.ddl」構建認證數據庫。

users.ddl 的定義如下:

create table users(
    username varchar_ignorecase(50) not null primary key,
    password varchar_ignorecase(50) not null,
    enabled boolean not null
);

create table authorities (
    username varchar_ignorecase(50) not null,
    authority varchar_ignorecase(50) not null,
    constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

使用此數據庫描述文本,在我們的數據庫中創(chuàng)建「用戶表」和「權限表」,并在 Spring Security 項目中配置 JDBC 數據源。

2.6.2 配置 JDBC 數據源

    @Autowired
    private DataSource dataSource;
    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

如此,我們便可以用數據庫中存儲的用戶名和密碼進行登錄校驗了。

3. 小結

本節(jié)我們介紹了用戶名密碼認證的實現(xiàn)方式,主要知識點如下:

Spring Security 用戶名密碼認證有多種實現(xiàn)方式,從認證方式角度看,可以分為表單認證、基本認證和數字證書認證,其中數字證書認證已經不適用現(xiàn)代的互聯(lián)網技術。從認證數據源角度,也可以分為內存認證、JDBC 數據庫認證和 LDAP 認證。

用戶名密碼認證是 Spring Security 框架中最基本的認證形式。下節(jié)開始我們將討論一種在移動應用被廣泛應用的認證方式:OAuth2.0 認證。