springSecurity自定義用戶認證邏輯


1. 創建項目

使用idea中的spring 初始化工具引入springbootspringsecruity初始化項目

最終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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo-spring-secruity</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo-spring-secruity</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<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>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.10</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

創建一個測試控制器

package com.example.demospringsecruity.controller;

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

/**
 * @author john
 * @date 2020/1/6 - 9:47
 */
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello spring secruity";
    }
}

運行項目

訪問<http://localhost:8081/hello>,會被跳轉到<http://localhost:8081/login>

輸入用戶名user和剛才運行項目時輸出的密碼,登錄成功,可以獲取到剛才預期的響應

2. 自定義登錄方式

package com.example.demospringsecruity.config;

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

/**
 * @author john
 * @date 2020/1/6 - 10:07
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表單登錄
//        http.formLogin()
        //  基本登錄
        http.httpBasic()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated();
    }
}

當瀏覽器發送一個請求后,首先會經過第一個過濾器,UsernamePassowordAuthenticationFilter,這個過濾器中,它會判斷你的請求是否帶usernamepassword這兩個參數,如果帶了就進行攔截驗證,如果沒有就進入到第二個過濾器BasicAuthenticationFilter,這個過濾器會判斷請求頭中是否含有需要驗證的信息,如果沒有進入下一個攔截器,最后到ExceptionTranslationFilter攔截器,它會捕獲FilterSecurityInterceptor拋出的異常,而FilterSecurityInterceptor會判斷這個請求是否校驗通過,權限是否通過,以上就是Spring Security框架的一個基本認證流程,FilterSecurityInterceptor是這個框架的最后一個攔截器,所有的請求都必須通過該攔截器的校驗。

3. 自定義用戶認證邏輯

1. 處理用戶信息獲取邏輯        UserDetailsService
2. 處理用戶校驗邏輯	          UserDetails
3. 處理密碼加密解密           PasswordEncoder

UserDetailsService

用戶信息獲取邏輯在springsecruity中是被封裝在UserDetailService接口中

package org.springframework.security.core.userdetails;

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

UserDetails

public interface UserDetails extends Serializable {
	Collection<? extends GrantedAuthority> getAuthorities();//權限的集合
	String getPassword();//密碼
	String getUsername();//用戶名
	boolean isAccountNonExpired();//賬戶是否沒過期 true-->沒過期
	boolean isAccountNonLocked();//賬戶是否沒鎖定 true-->沒被鎖定
	boolean isCredentialsNonExpired();//憑證是否沒過期 true-->沒過期
	boolean isEnabled();//賬戶是否可用
}

下面開始編寫具體代碼
MyUserDetailsService處理用戶信息獲取邏輯

package com.example.demospringsecruity.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author john
 * @date 2020/1/6 - 10:32
 */
@Component
@Slf4j
public class MyUserDetailsService implements UserDetailsService {
    //這里可以注入mapper或者repository的dao對象來實現數據校驗邏輯操作
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("用戶名:" + username);
        //這里密碼應該從數據庫中取出,暫時先使用加密生成
        String password = passwordEncoder.encode("123456");
        //User類是Spring內置的一個類,實現了UserDetails接口,而這個接口是UserDetailSerice的子接口
        return new User(username,
                password,
                true,        // 賬戶是否可用
                true,        // 賬戶是否過期
                true,        // 密碼是否過期
                true,        //賬戶是否被鎖定
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin") //授權集合
        );
    }
}

PasswordConfig處理密碼加密解密
注入PasswordEncoder

package com.example.demospringsecruity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author john
 * @date 2020/1/6 - 12:51
 */
//說明這個一個配置類,類似spring中的xml文件
@Configuration
public class PasswordConfig {

    //手動將PasswordEncoder注入到ioc容器中
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

測試在輸入用戶user密碼123456后成功獲取數據

上面的演示我使用了spring-security自己的UserDetails實現類User(org.springframework.security.core.userdetails.User),但實際開發中我們不可能這么用,因為根據實際的業務,往往會希望用戶信息表里會包含更多的數據,比如說電話,郵箱,公司職位等信息,那我們該如何去處理呢?

其實非常簡單,我們只要將我們自己的User表繼承spring-securityUser類(org.springframework.security.core.userdetails.User),再在MyUserDetailsService里只要返回我們自己的user即可.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM