New file |
| | |
| | | package com.jilongda.applet.security; |
| | | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.security.authentication.*; |
| | | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.security.core.AuthenticationException; |
| | | import org.springframework.security.core.userdetails.UserDetails; |
| | | import org.springframework.security.core.userdetails.UsernameNotFoundException; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * 身份验证提供者--->登录验证逻辑 |
| | | * <p> |
| | | * 不管是 implements AuthenticationProvider 还是 extends DaoAuthenticationProvider 区别不大 |
| | | * <p> |
| | | * DaoAuthenticationProvider 实现了 AuthenticationProvider 类 |
| | | * <p> |
| | | * 验证逻辑都是在 public Authentication authenticate(Authentication authentication) throws AuthenticationException {} 方法中 |
| | | * |
| | | * @author xiaochen |
| | | * @date 2021-01-02 20:17 |
| | | */ |
| | | @Slf4j |
| | | public class AuthenticationProvider extends DaoAuthenticationProvider { |
| | | |
| | | private SysUserDetailsService loadUserDetailsService; |
| | | private PasswordEncoder passwordEncoder; |
| | | |
| | | public AuthenticationProvider(SysUserDetailsService loadUserDetailsService, PasswordEncoder passwordEncoder) { |
| | | this.loadUserDetailsService = loadUserDetailsService; |
| | | this.passwordEncoder = passwordEncoder; |
| | | setUserDetailsService(loadUserDetailsService); |
| | | setPasswordEncoder(passwordEncoder); |
| | | } |
| | | |
| | | @Override |
| | | public Authentication authenticate(Authentication authentication) { |
| | | // 可以在此处覆写整个登录认证逻辑 |
| | | // [1] 获取 username 和 password |
| | | String userName = (String) authentication.getPrincipal(); |
| | | String password = (String) authentication.getCredentials(); |
| | | log.info("用户数据查询======================================"); |
| | | // [2] 使用用户名从数据库读取用户信息 |
| | | SecurityUserDetails userDetails = this.loadUserDetailsService.loadUserByUsername(userName); |
| | | log.info("用户数据查询======================================:{}", userDetails); |
| | | // 判断是否被封禁 |
| | | // userDetails.setEnabled(userDetails.getState()); |
| | | // [3] 检查用户信息 |
| | | if (Objects.isNull(userDetails)) { |
| | | throw new UsernameNotFoundException("用户账户不存在"); |
| | | // } else if (userDetails.isEnabled() || userDetails.getState()) { |
| | | // throw new DisabledException(userName + " 用户已被禁用或删除,请联系管理员"); |
| | | } else if (!userDetails.isAccountNonExpired()) { |
| | | throw new AccountExpiredException(userName + " 账号已过期"); |
| | | } else if (!userDetails.isAccountNonLocked()) { |
| | | throw new LockedException(userName + " 账号已被锁定"); |
| | | } else if (!userDetails.isCredentialsNonExpired()) { |
| | | throw new LockedException(userName + " 凭证已过期"); |
| | | } |
| | | // [4] 数据库用户的密码,一般都是加密过的 |
| | | String encryptedPassword = userDetails.getPassword(); |
| | | |
| | | // 根据加密算法加密用户输入的密码,然后和数据库中保存的密码进行比较 |
| | | if (!this.passwordEncoder.matches(password, encryptedPassword)) { |
| | | throw new BadCredentialsException("密码错误"); |
| | | } |
| | | // [5] 成功登陆,把用户信息提交给 Spring Security |
| | | // 把 userDetails 作为 principal 的好处是可以放自定义的 UserDetails,这样可以存储更多有用的信息,而不只是 username, |
| | | // 默认只有 username,这里的密码使用数据库中保存的密码,而不是用户输入的明文密码,否则就暴露了密码的明文 |
| | | // 不暴露密码 |
| | | // userDetails.setPassword(null); |
| | | UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, null); |
| | | // 设置详情 |
| | | //String userInfo = JsonUtils.toJsonString(userDetails); |
| | | usernamePasswordAuthenticationToken.setDetails(userDetails); |
| | | return usernamePasswordAuthenticationToken; |
| | | } |
| | | |
| | | @Override |
| | | protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) |
| | | throws AuthenticationException { |
| | | // 可以在此处覆写密码验证逻辑 |
| | | super.additionalAuthenticationChecks(userDetails, authentication); |
| | | } |
| | | } |