Spring security 02-自定義用戶登陸頁面和登陸處理邏輯

Spring security 系列博客目錄

對應源代碼

開篇

上一篇(在項目裏面引入spring-security會發生什麼)咱們將 Spring-seccurity 引入到了咱們的spring-boot工程中,沒有作多餘的配置,spring-security 就已經默認幫咱們配置了一個攔截器,應用啓動後,當咱們訪問應用提供的資源時,都會跳轉到 security 爲咱們提供的一個默認登錄頁,當咱們輸入security爲咱們提供的用戶名和密碼,登錄成功後,就能夠獲取咱們須要的資源。那麼問題來了!咱們如何自定義本身的登陸頁面,以及使用咱們本身的用戶信息去登陸呢?html

實戰

建立工程

爲了避免影響以前的版本,咱們這裏新建一個模塊 spring-security-02,以前的版本是spring-security-01. https://github.com/nimo10050/spring-security-sample/tree/master/spring-security-02git

引入依賴

依賴跟上個版本同樣,以下:github

<dependencies>
		<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>

	</dependencies>

新建 SpringSecurity 配置類

既然咱們須要自定義一些東西,只能經過額外配置的方式來實現。因此這裏引入了spring-security的配置類web

  • 添加 @Component註解spring

  • 添加 Spring-security 的註解 EnableWebSecurity 標記這是 security的 配置類數據庫

  • 繼承 WebSecurityConfigurerAdapter 重寫它的配置方法api

  • 重寫 configure(HttpSecurity http) 方法是爲了定義登錄頁ide

  • 重寫 configure(AuthenticationManagerBuilder auth) 是爲了定義登陸邏輯spring-boot

    package com.example.demo.config;
    
      import com.example.demo.config.service.UserDetailServiceImpl;
      import org.springframework.context.annotation.Bean;
      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
      import org.springframework.security.config.annotation.web.builders.HttpSecurity;
      import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      import org.springframework.stereotype.Component;
    
      [@Component](https://my.oschina.net/u/3907912)
      @EnableWebSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
      [@Override](https://my.oschina.net/u/1162528)
      protected void configure(HttpSecurity http) throws Exception {
    
      	http.csrf().disable();// 必須有, 否則會 403 forbidden
    
      	http.formLogin()
      			.loginPage("/loginPage.html")// 自定義登陸頁
      			.loginProcessingUrl("/form/login");// 自定義登陸 action, 名字隨便起
      			// passwordParameter("password") 配置 form 表單 密碼的 name 屬性值
      			// usernameParameter("username") 配置 form 表單 用戶名的 name 屬性值
    
      	// 訪問 "/form/login", "/loginPage.html"   放行
      	http.authorizeRequests().antMatchers("/form/login", "/loginPage.html").permitAll()
      			.anyRequest().authenticated();
      }
    
      /**
       * 配置 用戶登陸處理類
       *
       * [@param](https://my.oschina.net/u/2303379) auth
       * @throws Exception
       */
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      	/* 將用戶信息存儲到內存中
      	   實際上不會這樣作,瞭解下便可
      	auth.inMemoryAuthentication()
      			.withUser("zhangsan")
      			.password(passwordEncoder().encode("123456"))
      			.authorities("admin");*/
    
      	auth.userDetailsService(userDetailsService());
      }
    
      /**
       * 自定義登陸處理
       *
       * @return
       */
      @Bean
      public UserDetailsService userDetailsService() {
      	return new UserDetailServiceImpl();
      }
    
    
      /**
       * 加密工具
       * 2.x 版本的 spring-security-starter 必須加上
       *
       * @return
       */
      @Bean
      public PasswordEncoder passwordEncoder() {
      	return new BCryptPasswordEncoder();
      }
    
      }

UserDetailService 接口

經過重寫 UserDetailService 接口的 loadUserByUsername方法來實現登陸邏輯,在loadUserByUsername 方法裏咱們能夠讀取數據庫或者其餘存儲介質,來校驗咱們的用戶是否存在。最後將咱們實現的類配置到config方法中。工具

/**
 * 自定義登陸處理邏輯
 */
public class UserDetailServiceImpl implements UserDetailsService {

/*    @Autowired
private PasswordEncoder passwordEncoder;*/

/**
 * @param username 登陸頁面輸入的用戶名
 * @return
 * @throws UsernameNotFoundException
 */
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    // TODO 根據 username 去用戶表查詢出來用戶的信息,而後進行驗證

    // 驗證成功後,返回Spring-Security 提供的 User 對象
    // 對應三個構造參數依次是: 1.用戶名 2.密碼(通過 passwordEncoder 加密後的密碼) 3.權限列表
    return new User(username, "$2a$10$g1gzj4KvMNY1kMZT1xDx9ufLuaDvCFDpX.PdETx85zQwXI/Mn4ttC", AuthorityUtils.createAuthorityList("admin"));
}

public static void main(String[] args) {
    System.out.println(new BCryptPasswordEncoder().encode("123456"));// $2a$10$g1gzj4KvMNY1kMZT1xDx9ufLuaDvCFDpX.PdETx85zQwXI/Mn4ttC
}
}

其餘須要注意的點

  • 在 configure(HttpSecurity http) 方法中須要加上 http.csrf().disable();不用問爲何,加上就完事了。
  • 當咱們重寫了config 方法後,spring-security 就不會攔截咱們要訪問的資源了,因此須要從新配置下

http.authorizeRequests().antMatchers("/form/login","/loginPage.html").permitAll().anyRequest().authenticated();

  • 當咱們定義了UserDetailService,應用啓動時控制檯就不會打印默認密碼了。

  • 高版本的 security 必需要配置密碼加密工具類。否則會報錯

    passwordEncoder is null

總結

spring-security 提供的功能特別多,咱們須要選擇性地去使用 security 提供的 api,而後去定製咱們的需求。一步一步來,不要盲目地把別人寫好的案例拷貝到本身的項目中,一個成型的案例,裏面的配置每每都是一大堆,根本無從看起(我剛開始就是這樣,把別人的security案例中的每一個方法,每一個api都扣一遍,很費時間),英文官方文檔能看個大概(要怪本身閱讀文檔能力不夠),看了無數的相關博客,每一篇博客大概只有十分之一是我想要的。最後把這些知識碎片組合在一塊兒,通過本身編碼實現,纔有這一系列入門踩坑博客。但願能幫助有須要的人。

相關文章
相關標籤/搜索