环境:IDEA Mysql JPA Spring Boot 2.X
1.准备工作
在IDEA新建一个Springboot 引入
spring-boot-starter-data-jpa
spring-boot-starter-web
spring-boot-starter-security
spring-boot-devtools (开发时调试用)
mysql-connector-java
lombok
spring-boot-starter-test
- 写一个系统用户实体 实现 UserDetails 接口
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysUser implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String realName;
@Column(unique = true)
private String username;
private String password;
public SysUser(String realName, String username, String password) {
this.realName = realName;
this.username = username;
this.password = password;
}
/**
* 获取用户权限信息
*
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
/**
* 是否过期
*
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 是否被锁定
*
* @return
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 密码是否过期
*
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 石头弃用
*
* @return
*/
@Override
public boolean isEnabled() {
return true;
}
}
- 编写配置类如下
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.....
}
- 编写Repository
@Repository
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
Optional<SysUser> findByUsername(String username);
}
- 编写一个简单的测试类
@RestController
public class IndexController {
@GetMapping("/")
public String hello() {
return "Hello Spring World";
}
- 开干!第一种:在WebSecurityConfig配置类中 下面的密码加密也要
/**
* ====================================================
* 自定义UserDetailService
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new CustomUserDetailsService(sysUserRepository));
}
/**
* 使用BCrypt座位密码编码加密算法
*
* @return
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- 测试:编写一个bean加入一个用户
@Bean
CommandLineRunner createUser(SysUserRepository sysUserRepository, PasswordEncoder passwordEncoder) {
return args -> {
SysUser user = new SysUser("test", "Agitator", passwordEncoder.encode("123"));
sysUserRepository.save(user);
};
}
- 访问localhost:8080 进行测试 自己感受
- 第二种:自定义authenticationProvider 编写一个类
/**
* 自定义认证提供程序
*/
public class CustomAuthenticationProvider implements AuthenticationProvider {
SysUserRepository sysUserRepository;
PasswordEncoder passwordEncoder;
public CustomAuthenticationProvider(SysUserRepository sysUserRepository, PasswordEncoder passwordEncoder) {
this.sysUserRepository = sysUserRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String usernameFormRequest = authentication.getName();
// 获取凭证
String passwordFormPassword = authentication.getCredentials().toString();
Optional<SysUser> sysUserOptional = sysUserRepository.findByUsername(usernameFormRequest);
SysUser sysUser = sysUserOptional.orElseThrow(() -> new UsernameNotFoundException("username not found"));
// 校验权限和凭证
if (passwordEncoder.matches(passwordFormPassword, sysUser.getPassword())
&& sysUser.isAccountNonExpired()
&& sysUser.isAccountNonLocked()
&& sysUser.isCredentialsNonExpired()
&& sysUser.isEnabled()) {
return new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword(), sysUser.getAuthorities());
} else {
// 抛出凭证异常
throw new BadCredentialsException("Bad Credentials");
}
}
/**
* 审明当前自定义的AuthenticationProvider 认证提供者 能处理的 Authentication 认证类型为 UsernamePasswordAuthenticationToken
*
* @param authentication
* @return
*/
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
- 在web配置类中注册
/**
* ======================================================
* 自定义 AuthenticationProvider
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new CustomAuthenticationProvider(sysUserRepository, passwordEncoder()));
}
- 第几种我忘了:前后端分离常用 Http基础认证 在上面其中一种的基础上 添加这个代码
/**
* 基于Http认证 重要!!!!!!! 前后端分离好用!!!
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated() // 所有请求在认证后才能访问
.and()
// 设置登录方式为HttpBasic 入口为 authenticationEntryPoint
.httpBasic().authenticationEntryPoint(authenticationEntryPoint());
}
/**
* http认证需要
*
* @return
*/
@Bean
AuthenticationEntryPoint authenticationEntryPoint() {
// BasicAuthenticationEntryPoint 将认证信息放在头部,当认证未通过时放回401
BasicAuthenticationEntryPoint authenticationEntryPoint = new BasicAuthenticationEntryPoint();
authenticationEntryPoint.setRealmName("test");
return authenticationEntryPoint;
}
-
http认证测试方法:postman 或者 apipost
- 在postman里面找到Authorization便签
- 使用Basic 验证方法
- 笔者用的是apiPost