安全框架Spring Security(二)——自定义用户认证逻辑

简介

上一篇文章中,我们可以看到Spring Boot只需要配置spring-cloud-starter-oauth2依赖,就自动帮我们把资源保护起来。Spring Security 5以后默认使用formLogin的方式登陆。但是之前使用的默认配置中,用户名和密码都是Spring Security默认提供给我们的。那么我们如何自定义用户的认证逻辑呢?这里就涉及到Spring Security的配置了。

配置

1.继承WebSecurityConfigurerAdapter类

这个是Spring Security的整体配置类

import com.marvin.demo.spring.cloud.auth.service.CloudUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @Author Marvin
 * @Description 身份认证配置
 * @Date 17:14 2019-06-04
 * @Param
 * @return
 **/
@Configuration
@EnableWebSecurity
public class CloudSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CloudUserDetailsService userDetailsService;
    /**
     * 密码加密方式
     **/
    @Bean
    public PasswordEncoder passwordEncoder() {
        //Spring Security 5推荐使用方式
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    /**
     * 需要配置这个支持password模式
     * support password grant type
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.formLogin() //使用formLogin的方式登陆
               .and()
               .authorizeRequests()
               .anyRequest().authenticated()  //任何请求都需要身份认证
               .and().csrf().disable();    //禁用CSRF
    }

}

2.实现UserDetailsService接口

UserDetailsService主要是用于验证用户名、密码和授权。

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.Service;

import java.util.Collection;

/**
 * @Author Marvin
 * @Description 基于spring security的用户信息服务
 * @Date 17:16 2019-06-04
 * @Param
 * @return
 **/
@Service
public class CloudUserDetailsService implements UserDetailsService {

	@Autowired
	private PasswordEncoder passwordEncoder;

	/**
	 * @Author Marvin
	 * @Description 校验用户信息
	 * @Date 17:16 2019-06-04
	 * @Param [username] 页面输入的账号
	 * @return org.springframework.security.core.userdetails.UserDetails
	 **/
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO 可以定义用户的身份校验,数据层的一些操作

		//返回的用户名和密码需要和我们页面输入的用户名密码匹配
		return new User(username, passwordEncoder.encode("123456"), 
			AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
	}
}

效果及说明

效果

上面的UserDetailsService中我们返回的是输入的用户名,密码是123456
首先访问 http://localhost:9999/ 发现资源收到保护,自动跳转到 http://localhost:9999/loginspring oauth2自定义认证模式 springsecurity自定义用户认证_ide
输入账号密码,我这里故意输错,提示“Bad credentials” ,意思是“坏的凭证”,就是提醒我密码输入错误了。
spring oauth2自定义认证模式 springsecurity自定义用户认证_ide_02
输入正确密码后,跳转到原来访问的地址 http://localhost:9999/ ,大功告成,我么已经可以自定义配置我们用户的认证逻辑了。

说明

上面的效果可以看出,我们在UserDetailsService的 loadUserByUsername方法中配置的账号密码生效了,所以说UserDetailsService是用于验证用户名、密码和授权的。上面看到,我们需要对密码进行加密后才放到User对象中,其中使用到Spring Security自带的PasswordEncoder加密器。如果不加密,Spring Security验证是不通过的哦!这可以就是安全框架的态度吧。