spring security的配置类:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES;
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class SecurityConfiguration {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize ->
{
try {
authorize//匿名访问路径
.requestMatchers("/oauth2/anonymous/**")
.permitAll()
.anyRequest().authenticated().and()
.oauth2ResourceServer()
.jwt();
} catch (Exception e) {
e.printStackTrace();
}
}
)
.formLogin().loginPage("/login").permitAll()
.and().logout(logout -> logout.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(COOKIES))));
http.csrf().disable();
http.headers().frameOptions().disable();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
自定义用户类、角色类:user、role
import com.example.oauth2.role.entity.Role;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
import java.util.Set;
@Entity
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String mobile;
private String password;
private Boolean disabled;
private Boolean locked;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(nullable = false, updatable = false)
@CreatedDate
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@LastModifiedDate
private LocalDateTime updateTime;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "userId"),
inverseJoinColumns = @JoinColumn(name = "roleId")
)
@JsonIgnore
private Set<Role> roles;
}
import com.example.oauth2.user.entity.User;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
import java.util.Set;
@Entity
@EntityListeners(AuditingEntityListener.class)
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Boolean disabled;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(nullable = false, updatable = false)
@CreatedDate
private LocalDateTime createTime;
@ManyToMany(mappedBy = "roles")
private Set<User> users;
}
import com.example.oauth2.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByMobile(String mobile);
}
import com.example.oauth2.exception.UserExistedException;
import com.example.oauth2.exception.UserNotFoundException;
import com.example.oauth2.user.entity.User;
import com.example.oauth2.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public User getByMobile(String mobile){
return userRepository.findByMobile(mobile).orElseThrow(()->new UserNotFoundException("不存在这样的用户"));
}
public void save(User user){
Assert.notNull(user.getMobile(), "电话号码不能为空");
Optional<User> userOptional = userRepository.findByMobile(user.getMobile());
if (userOptional.isPresent()){
throw new UserExistedException("该用户已存在,不能重复创建");
}
userRepository.save(user);
}
public User getById(Integer id){
Assert.notNull(id, "查询主键不能为空");
Optional<User> userOptional = userRepository.findById(id);
if (userOptional.isPresent()){
return userOptional.get();
}
throw new UserNotFoundException("不存在的用户主键:" + id);
}
public List<User> getAll(){
return userRepository.findAll();
}
}
spring security的账户安全认证相关类:SecurityUser、SecurityUserDetailsService
import com.example.oauth2.role.entity.Role;
import com.example.oauth2.user.entity.User;
import lombok.Getter;
import lombok.Setter;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
public class SecurityUser {
private Integer id;
private String username;
private String password;
private String phone;
private Boolean disabled;
private Boolean locked;
private Set<Role> roles;
public SecurityUser(User user){
this.id = user.getId();
this.username = user.getName();
this.password = user.getPassword();
this.phone = user.getMobile();
this.disabled = user.getDisabled();
this.locked = user.getLocked();
Set<Role> roles = new HashSet<>();
if (null != user.getRoles() && user.getRoles().size() > 0){
for (Role role: user.getRoles()){
if (!role.getDisabled()){
roles.add(role);
}
}
}
this.roles = roles;
}
}
import com.example.oauth2.exception.UserNotFoundException;
import com.example.oauth2.security.user.SecurityUser;
import com.example.oauth2.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Service;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class SecurityUserDetailsService implements UserDetailsService {
private final UserService userService;
@Override
public UserDetails loadUserByUsername(String mobile) {
try{
SecurityUser user = new SecurityUser(userService.getByMobile(mobile));
return new User(
user.getPhone(),
user.getPassword(),
!user.getDisabled(),
true,
true,
!user.getLocked(),
user.getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList())
);
}catch (UserNotFoundException e){
throw new UsernameNotFoundException(e.getMessage());
}
}
}
自定义异常类:UserNotFoundException、UserExistedException
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message){
super(message);
}
public UserNotFoundException(String message, Throwable cause){
super(message, cause);
}
}
public class UserExistedException extends RuntimeException{
public UserExistedException(String message){
super(message);
}
public UserExistedException(String message, Throwable cause){
super(message, cause);
}
}