springsecurity基于数据库中的用户信息实现登陆
springsecurity简介
Spring Security是一个基于Java的开源框架,用于在Java应用程序中提供身份验证和授权的安全性。它是构建安全性功能的强大框架,可用于保护Web应用程序、REST API和其他类型的后端服务。
Spring Security提供了一套全面的安全性特性,包括用户身份验证、访问控制、密码管理、会话管理和跨站点请求伪造(CSRF)防护等。它还支持多种认证方式,包括基于表单的身份验证、基于HTTP基本认证、基于OAuth和OpenID Connect等。使用Spring Security,可以轻松地将安全性集成到你的应用程序中。它提供了灵活的配置选项和可扩展的API,使你能够根据具体的需求来定制和实现安全性功能。此外,Spring Security还与其他Spring框架和技术无缝集成,如Spring Boot、Spring MVC和Spring Data等。
实现步骤
1. 创建一个用户实体类(User Entity),用于表示存储在数据库中的用户信息。该实体类应包含用户名、密码和角色等必要的属性。
2. 创建一个用户详细信息服务类(UserDetailsService),实现Spring Security提供的 `UserDetailsService` 接口。该类应该实现 `loadUserByUsername` 方法,用于根据用户名从数据库中加载用户详细信息。
3. 创建一个密码编码器(Password Encoder)用于对用户密码进行加密。Spring Security提供了多种密码编码器实现,如BCryptPasswordEncoder、PasswordEncoder等。
4. 在Spring Security的配置类中,通过继承 `WebSecurityConfigurerAdapter` 并覆写 `configure` 方法,进行安全配置。:
- 使用 `.userDetailsService(userDetailsService)` 方法指定你实现的用户详细信息服务类。
- 使用 `.passwordEncoder(passwordEncoder)` 方法指定你选择的密码编码器。
- 使用 `.jdbcAuthentication()` 方法启用基于数据库的身份验证。
- 使用 `.dataSource(dataSource)` 方法指定你的数据源,以便Spring Security可以连接到数据库。
5. 在登录页面的表单中,需要包含用户名和密码的输入字段,并将表单的提交地址指向Spring Security提供的默认登录地址( `/login` )。
具体实现:
用户详细信息服务类(UserDetailsService),实现Spring Security提供的 UserDetailsService
接口。该类应该实现 loadUserByUsername
方法,用于根据用户名从数据库中加载用户详细信息。
@Service
public class MyUserDetailServiceImpl implements UserDetailsService {
@Autowired
private SysUserService sysUserService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserService.getByUserName(username);//根据用户名查询数据;也可以直接用getone查询
if (sysUser==null){//没有找打该用户
throw new UsernameNotFoundException("账户或密码错误");
}else if ("1".equals(sysUser.getStatus())){//该用户的Status状态为1
throw new UserCountLockException("账户已经被封禁,请联系管理员!");//自定义异常
}
//因为这个函数规定返回的UserDetails类型,为了方便,我们返回其实现类
return new User(sysUser.getUsername(),sysUser.getPassword(),getUserAuthority(sysUser.getId()));
}
private List<GrantedAuthority> getUserAuthority(Long id) {
return new ArrayList<>();
}
}
密码编码器(Password Encoder)用于对用户密码进行加密
//默认密码加密配置
@Bean
BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
在Spring Security的配置类中,通过继承 WebSecurityConfigurerAdapter
并覆写 configure
方法,进行安全配置。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private LoginFailureHandler loginFailureHandler;
@Autowired
private MyUserDetailServiceImpl myUserDetailService;
// 定义白名单URL路径数组
private static final String URL_WHITELIST[] = {
"/login",
"/logout",
"/captcha",
"/password",
"/image/**",
"/test/**"
} ;
//默认密码加密配置
@Bean
BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 配置应用程序的安全规则
* 开启跨域资源共享(CORS)功能,并关闭跨站请求伪造(CSRF)攻击防护
* 配置登录相关设置
* 禁用会话(session)的创建
* 配置拦截规则
* @param http HttpSecurity对象,用于配置应用程序的安全规则
* @throws Exception 配置过程中可能抛出的异常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors() // 开启CORS功能(跨域)
.and()
.csrf().disable() // 关闭CSRF攻击防护
.formLogin() // 配置登录相关设置
.successHandler(loginSuccessHandler) // 自定义登录成功处理器
.failureHandler(loginFailureHandler) // 自定义登录失败处理器
// .and()
// .logout() // 配置注销设置(如果需要)
// .logoutSuccessHandler() // 自定义注销成功处理器(如果需要)
.and()
//session禁用配置
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用会话的创建(无状态)
.and()
.authorizeRequests()
.antMatchers(URL_WHITELIST).permitAll() // 白名单中的URL路径允许无需身份验证/permitAll放行所有
.anyRequest().authenticated(); // 其他所有请求需要身份验证
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailService);
}
}
拓展
自定义的登陆成功处理器
在上述代码中有一个自定义的登陆成功处理器。具体代码可以参考如下:
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
/**
* 登录失败处理器
*
* @param httpServletRequest HTTP请求
* @param httpServletResponse HTTP响应
* @param e 认证异常
* @throws IOException IO异常
* @throws ServletException Servlet异常
*/
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
// 设置响应内容类型为JSON,并且编码为UTF-8
httpServletResponse.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
// 获取认证异常的错误信息
String message=e.getMessage();
// 如果是BadCredentialsException异常,则将错误信息设置为"用户名或者密码错误!"
if(e instanceof BadCredentialsException){
message="用户名或者密码错误!";
}
// 将错误信息以JSON格式写入响应输出流中
outputStream.write(JSONUtil.toJsonStr(R.error(message)).getBytes("UTF8"));
outputStream.flush();
outputStream.close();
}
}
// 这段代码是一个登录失败处理器的实现类。当用户认证失败后,会执行该类中的onAuthenticationFailure方法。该方法的作用是在HTTP响应中返回认证失败的错误信息。
// 具体代码解释如下:
// - 设置响应内容类型为JSON,并且编码为UTF-8。
// - 获取HTTP响应的输出流。
// - 获取认证异常的错误信息。
// - 如果认证异常是BadCredentialsException类型,则将错误信息设置为"用户名或者密码错误!"。
// - 将错误信息以JSON格式写入响应输出流中。
// - 刷新输出流并关闭。
自定义的登陆失败处理器
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
/**
* 登录成功处理器
*
* @param httpServletRequest HTTP请求
* @param httpServletResponse HTTP响应
* @param authentication 认证信息
* @throws IOException IO异常
* @throws ServletException Servlet异常
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
// 设置响应内容类型为JSON,并且编码为UTF-8
httpServletResponse.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
// 定义用户名
String username="user";
// 生成JWT令牌
String token = JwtUtils.genJwtToken(username);
// 将登录成功信息和令牌写入响应输出流中
outputStream.write(JSONUtil.toJsonStr(R.ok("登录成功").put("authorization",token)).getBytes());
outputStream.flush();
outputStream.close();
}
}
// 这段代码是一个登录成功处理器的实现类。当用户成功认证后,会执行该类中的onAuthenticationSuccess方法。该方法的作用是在HTTP响应中返回登录成功的信息和生成的JWT令牌。
// 具体代码解释如下:
// - 设置响应内容类型为JSON,并且编码为UTF-8。
// - 获取HTTP响应的输出流。
// - 定义用户名为"user"(通常应该从认证信息中获取)。
// - 调用JwtUtils类的genJwtToken方法生成JWT令牌。
// - 将登录成功信息和令牌以JSON格式写入响应输出流中。
// - 刷新输出流并关闭。
用户详细信息服务类(UserDetailsService)中的自定义异常
public class UserCountLockException extends AuthenticationException {
public UserCountLockException(String msg, Throwable t) {
super(msg, t);
}
public UserCountLockException(String msg) {
super(msg);
}
}