安全框架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/login
输入账号密码,我这里故意输错,提示“Bad credentials” ,意思是“坏的凭证”,就是提醒我密码输入错误了。
输入正确密码后,跳转到原来访问的地址 http://localhost:9999/ ,大功告成,我么已经可以自定义配置我们用户的认证逻辑了。
说明
上面的效果可以看出,我们在UserDetailsService的 loadUserByUsername方法中配置的账号密码生效了,所以说UserDetailsService是用于验证用户名、密码和授权的。上面看到,我们需要对密码进行加密后才放到User对象中,其中使用到Spring Security自带的PasswordEncoder加密器。如果不加密,Spring Security验证是不通过的哦!这可以就是安全框架的态度吧。