我正在使用oauth创建一个Spring boot应用程序,现在我可以登录github,但我想要一个基于角色的应用程序,所以有些路由只能由role_admin访问,而其他路由可以由role_user访问,我一直在尝试一些东西,但我的代码看起来有点混乱,所以我感谢任何帮助! 现在,在 CustomOAuth2User 类的 getAuthorities 方法中,它显示了 Set Roles = getUserRoles();为空,因此它默认所有用户角色为 role_user,因此我可以访问需要此类角色的路由,但不能访问管理员路由,即使我使用 role_admin 创建用户也是如此。
安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomOAuth2UserService oauthUserService;
@Autowired
private UserRepository userRepository;
@Autowired
private UserService userService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> {
auth.requestMatchers(HttpMethod.GET, "/userinfo").hasRole("ADMIN");
auth.requestMatchers(HttpMethod.GET, "/").hasRole("USER");
auth.anyRequest().authenticated();
})
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo.userService(oauthUserService)).successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
CustomOAuth2User oauthUser = (CustomOAuth2User) authentication.getPrincipal();
String github_id = oauthUser.getAttributes().get("id").toString();
Optional<User> userExistOp = userRepository.findByIdentifier(github_id);
if(!userExistOp.isPresent()) {
//all user are saves with role User
UserDTO userDTO = new UserDTO(oauthUser.getName(),"username", oauthUser.getAttributes().get("id").toString(), oauthUser.getAttributes().get("avatar_url").toString(), Role.ADMIN);
userService.create(userDTO);
}
response.sendRedirect("/");
}
})
)
.build();
}
}
自定义OAuth2用户服务
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User user = super.loadUser(userRequest);
return new CustomOAuth2User(user);
}
}
自定义Oauth2User
public class CustomOAuth2User implements OAuth2User {
private OAuth2User oauth2User;
public CustomOAuth2User(OAuth2User oauth2User) {
this.oauth2User = oauth2User;
}
@Override
public Map<String, Object> getAttributes() {
return oauth2User.getAttributes();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Role> roles = getUserRoles();
System.out.println("User roles:");
for (Role role : roles) {
System.out.println(role.name());
}
if (roles != null && !roles.isEmpty()) {
// Convert roles to GrantedAuthority objects
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.name()))
.collect(Collectors.toList());
} else {
// Provide a default role if user roles are not available
return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
}
}
@Override
public String getName() {
return oauth2User.getAttribute("name");
}
// Helper method to retrieve user roles from OAuth2User attributes
private Set<Role> getUserRoles() {
// Assuming roles are stored as an attribute with key "roles" in OAuth2User attributes
Collection<String> roleStrings = (Collection<String>) oauth2User.getAttribute("roles");
return roleStrings != null ?
roleStrings.stream()
.map(Role::valueOf) // Convert role string to Role enum
.collect(Collectors.toSet()) :
Collections.emptySet();
}
public String getEmail() {
return oauth2User.<String>getAttribute("email");
}
}
用户模型
@Entity
@Table(name="users")
@Data
@Setter
public class User implements UserDetails {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String name;
private String username;
private String identifier;
private String avatar;
private Role role;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if (this.role == Role.ADMIN) {
return List.of(new SimpleGrantedAuthority("ROLE_ADMIN"), new SimpleGrantedAuthority("ROLE_USER"));
}
return List.of(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
认证服务
@Service
public class AuthService implements UserDetailsService{
UserRepository userRepository;
public AuthService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String identifier) throws UsernameNotFoundException {
Optional<User> userOp = userRepository.findByIdentifier(identifier);
if (!userOp.isPresent()) {
throw new UsernameNotFoundException("User not found with GitHub user ID: " + identifier);
}
User user = userOp.get();
// Construct UserDetails object with user roles
return org.springframework.security.core.userdetails.User
.withUsername(String.valueOf(user.getIdentifier())) // GitHub user ID
.password(user.getPassword())
.authorities(user.getAuthorities())
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.disabled(true)
.build();
}
}
Pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ecommerce</groupId>
<artifactId>e-commerce</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>e-commerce</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
你应该做的是使用你自己的授权服务器(Keycloak?Auth0?Amazon cognito?有很多选择)。这个新的授权服务器将负责保留角色并将其添加到令牌中。然后,您只需在 Spring 客户端和资源服务器中手动配置权限映射即可。