SpringBoot(3)集成Spring Security 5.0.11 自定义认证逻辑

Spring Security 框架默认的认证业务逻辑是不能满足我们产品或项目的需求的,这时候如果我们使用Spring Security 框架就需要自定义用户认证逻辑。
自定义认证逻辑,我们需要关心几个问题:

  • 如何处理获取用户信息
  • 如何处理校验用户信息
  • 如何处理密码加密解密

Spring Security自定义认证逻辑

1.如何处理获取用户信息

Spring Security 提供了UserDetailsService 接口,用来处理用户信息获取,我们只要实现这个接口
,对loadUserByUsername方法进行实现,返回UserDetails 对象即可,在这个方法中,我们可以通过username字段(帐号)去数据库查找相应的用户信息。

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

2.如何处理校验用户信息

同样用户校验信息,Spring Security 提供了UserDetails接口,Spring Security 对 UserDetails接口有默认实现User,我们直接使用它提供的即可

public interface UserDetails extends Serializable {

	Collection<? extends GrantedAuthority> getAuthorities();

	/**
	 * 密码
	 */
	String getPassword();

	/**
	 * 帐号
	 */
	String getUsername();

	/**
	 * 账户是否过期
	 */
	boolean isAccountNonExpired();

	/**
	 * 用户是否被锁定
	 */
	boolean isAccountNonLocked();

	/**
	 * 用户是否已过期
	 */
	boolean isCredentialsNonExpired();

	/**
	 * 用户是否被禁用
	 */
	boolean isEnabled();
}

3.如何处理密码加密解密

Spring Security 提供了 PasswordEncoder 接口,来处理密码加密和匹配问题。密码加密使我们来调用的,如果在用户注册的是有没有调用会密码匹配不上。

public interface PasswordEncoder {

	/**
	 * 这个方法当用户注册的时候调用
	 */
	String encode(CharSequence rawPassword);
	/**
	 * 这个方法是使用登录输入的密码和用户真正的使用的密码进行匹配
	 */
	boolean matches(CharSequence rawPassword, String encodedPassword);

}

Spring Security 自定义认证步骤

我的环境

  • SpringBoot 2.0.8
  • Spring Security 5.0.11
  • JDK 1.8
  • Eclipse 4.11.0
  • Maven 3.5.4
  • Windows 10

项目结构

SpringBoot(3)集成Spring Security 5.0.11 自定义认证逻辑

项目pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.com.witsystem</groupId>
	<artifactId>security</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<!-- 管理依赖 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.spring.platform</groupId>
				<artifactId>platform-bom</artifactId>
				<version>Cairo-SR7</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.RELEASE</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/libs-milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	
	<dependencies>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>
</project>

UserDetailsServiceImpl

package cn.com.witsystem.security.custom;

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;

import lombok.extern.slf4j.Slf4j;

/**
 * 处理用户信息获取
 */
@Component
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService{

	@Autowired
	PasswordEncoder passwordEncoder;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		log.info(username);
		//1.通过username(帐号)查找用户信息
		//2.通过获取的用户信息封装实现UserDetails接口的User对象 ,封装User对象的3个参数
		//passwordEncoder.encode("123456") 对密码就行加密操作
		return new User(username, passwordEncoder.encode("123456"), true, true, true, true, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
	}

}

SecurityConfig

package cn.com.witsystem.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import cn.com.witsystem.security.custom.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Autowired
	UserDetailsServiceImpl detailsServiceImpl;
	
	@Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.formLogin()
			.and()
			.authorizeRequests()
			.anyRequest()
			.authenticated();
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(detailsServiceImpl)
			.passwordEncoder(passwordEncoder());
	}

}

SecurityApplication

package cn.com.witsystem.security;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class SecurityApplication {
	
	public static void main(String[] args) throws Exception {
		SpringApplication.run(SecurityApplication.class, args);
	}
	
	@GetMapping("/hello")
	public String hello() {
		return "hello!";
	}
}

application.yml

### 服务器端口配置  
server:
  port: 8080

启动测试

访问 http://localhost:8080/hello

SpringBoot(3)集成Spring Security 5.0.11 自定义认证逻辑
SpringBoot(3)集成Spring Security 5.0.11 自定义认证逻辑