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

首頁 慕課教程 Spring Security Spring Security Spring Security 用戶名密碼認(rèn)證

Spring Security 用戶名密碼認(rèn)證實(shí)例

1. 前言

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

用戶名、密碼認(rèn)證被廣泛應(yīng)用于 PC 端的 Web 應(yīng)用和客戶端應(yīng)用,比如登陸網(wǎng)站,又比如 QQ 桌面客戶端。

圖片描述

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

從認(rèn)證數(shù)據(jù)源角度分類,也可以將認(rèn)證分為:

  1. 使用內(nèi)存存儲;
  2. 使用關(guān)系型數(shù)據(jù)庫存儲;
  3. 自定義存儲;
  4. LDAP 存儲。

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

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

2. 實(shí)例講解

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

  1. 修改 Hello World 模板工程的目錄名稱為 UsernamePasswordSample;
  2. 修改 pom.xml 文件,將基礎(chǔ)信息部分改為如下形式:
<?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("當(dāng)前登錄用戶為:「%s」", principal.getName());
    }
}
  1. 在項(xiàng)目根目錄控制臺輸入命令 mvn spring-boot:run,如看到以下輸出代表配置正確。

圖片描述

2.2 表單認(rèn)證

2.2.1 表單認(rèn)證的過程說明

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

表單認(rèn)證可分為以下步驟:

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

圖片描述

圖 2 表單登錄流程

當(dāng)用戶提交登錄信息,認(rèn)證服務(wù)器端的 UsernamePasswordAuthenticationFilter 就會被執(zhí)行。

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

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

2.2.2 表單認(rèn)證的開啟

默認(rèn)情況下,Spring Security 開啟了表單認(rèn)證功能。如果我們需要顯式配置,可用如下方式實(shí)現(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 ,網(wǎng)頁會自動跳轉(zhuǎn)到登錄頁面。

圖片描述

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

圖片描述

提交登錄后,通過認(rèn)證,我們將在瀏覽器看到當(dāng)前登錄的用戶名。

當(dāng)前登錄用戶為:「user」

2.2.3 表單認(rèn)證的配置

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

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

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

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

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

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

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

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

  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 ,此時(shí)跳轉(zhuǎn)到我們新建的登錄頁面。

圖片描述

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

2.3 基本認(rèn)證

2.3.1 基本認(rèn)證的流程

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

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

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

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

在 Spring Security 中,具體的認(rèn)證過程如下:

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

當(dāng)客戶端收到 WWW-Authenticate 頭后,客戶端提供用戶名和密碼參數(shù)用于認(rèn)證。

2.3.2 基本認(rèn)證的配置

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

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

2.4 數(shù)字認(rèn)證

數(shù)字認(rèn)證在新型應(yīng)用中已不建議使用,因?yàn)檫@種方式下,用戶的敏感信息,比如密碼等都需要以明文形式存在,因此數(shù)字認(rèn)證方式并不安全。

數(shù)字認(rèn)證對應(yīng)的認(rèn)證過濾器為:DigestAuthenticationFilter

2.5 在內(nèi)存中配置用戶名密碼

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

內(nèi)存認(rèn)證添加用戶的方式如下,在 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 工具,在控制臺將密碼轉(zhuǎn)換為密文。

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

2.6 使用數(shù)據(jù)庫管理用戶名密碼

Spring Security 支持使用數(shù)據(jù)庫作為認(rèn)證數(shù)據(jù)源,并且提供了默認(rèn)數(shù)據(jù)模型。

2.6.1 默認(rèn)的數(shù)據(jù)模型

使用 JDBC 數(shù)據(jù)源最簡單直接的方法就是使用 Spring Security 提供的默認(rèn)數(shù)據(jù)模型「users.ddl」構(gòu)建認(rèn)證數(shù)據(jù)庫。

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);

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

2.6.2 配置 JDBC 數(shù)據(jù)源

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

如此,我們便可以用數(shù)據(jù)庫中存儲的用戶名和密碼進(jìn)行登錄校驗(yàn)了。

3. 小結(jié)

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

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

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