访问被拒绝 HasRole 未调用 getAuthorities()

问题描述 投票:0回答:1

我试图将路径限制为仅ADMIN。到目前为止,但这给了我<403 Forbidden>错误:

此应用程序没有 /error 的显式映射,因此您将其视为后备。 2024 年 4 月 8 日星期一 01:49:02 美国东部时间 出现意外错误(类型=禁止,状态=403)。

安全配置

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
    private final UserService userService;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        return http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/").permitAll()
                        .requestMatchers("/login**", "/error**", "/resource/**").permitAll()
                        .requestMatchers("/admin/**").hasRole("ADMIN")

                        .anyRequest().authenticated()
                )
                .formLogin(withDefaults())
                .oauth2Login((userInfo) -> userInfo
                        .userInfoEndpoint((config) -> config.oidcUserService(userService))
                )
                .build();
    }

用户

@Entity
@Table(name = "user")
@Data
@NoArgsConstructor
public class UserEntity implements Serializable, UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(unique = true)
    private String username;

    @Column
    private String password;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
    @JoinTable(name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private Set<Role> roles = new HashSet<>();

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRoles();
    }

角色

@Entity
@Table(name = "role")
@AllArgsConstructor
@NoArgsConstructor
@Getter @Setter
public class Role implements GrantedAuthority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(unique = true)
    private String name;

    @Override
    public String getAuthority() {
        return name;
    }
}

用户服务

@Service
@AllArgsConstructor
public class UserService extends OidcUserService {
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser oidcUser = super.loadUser(userRequest);
        try {
            return processOidcUser(userRequest, oidcUser);
        } catch (Exception e) {
            throw new InternalAuthenticationServiceException(e.getMessage(), e.getCause());
        }
    }

    private OidcUser processOidcUser(OidcUserRequest userRequest, OidcUser oidcUser) {
        GoogleUserInfo googleUserInfo = new GoogleUserInfo(oidcUser.getAttributes());

        Optional<UserEntity> userOptional = userRepository.findByUsername(googleUserInfo.getEmail());
        if (userOptional.isEmpty()) {
            UserEntity user = new UserEntity();
            user.setUsername(googleUserInfo.getEmail());
            user.setPassword(googleUserInfo.getName());
            Role role = roleRepository.findByName("ADMIN");
            user.getRoles().add(role);
            userRepository.save(user);
        }
        return oidcUser;
    }
}

我尝试使用 accessDeniedHandler 进行调试,但找不到出路。

这也没有帮助:

.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/admin/**").hasAuthority("ROLE_ADMIN")
.requestMatchers("/admin/**").hasAuthority("ADMIN")

感谢您的帮助!有任何意见欢迎欢迎

java spring spring-security oauth access-denied
1个回答
0
投票

我在 processOidcUser 中返回相同的 oidcUser。所以我为它创建了 CustomOidcUser。

public class CustomOidcUser implements OidcUser {
    private final OidcUser oidcUser;
    private final Set<Role> roles;

    @Override
    public Map<String, Object> getClaims() {
        return oidcUser.getClaims();
    }

    @Override
    public OidcUserInfo getUserInfo() {
        return oidcUser.getUserInfo();
    }

    @Override
    public OidcIdToken getIdToken() {
        return oidcUser.getIdToken();
    }

    @Override
    public Map<String, Object> getAttributes() {
        return oidcUser.getAttributes();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles();
    }

    @Override
    public String getName() {
        return oidcUser.getFullName();
    }
}

然后更改 UserService 为 loadUser 返回自定义 oidcUser。

public class UserService extends OidcUserService {
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser oidcUser = super.loadUser(userRequest);
        try {
            return processOidcUser(oidcUser);
        } catch (Exception e) {
            throw new InternalAuthenticationServiceException(e.getMessage(), e.getCause());
        }
    }

    private OidcUser processOidcUser(OidcUser oidcUser) {
        GoogleUserInfo googleUserInfo = new GoogleUserInfo(oidcUser.getAttributes());
        Optional<UserEntity> userOptional = userRepository.findByUsername(googleUserInfo.getEmail());
        if (userOptional.isEmpty()) {
            UserEntity user = new UserEntity();
            user.setUsername(googleUserInfo.getEmail());
            user.setPassword(googleUserInfo.getName());
            Role role = roleRepository.findByName("USER");
            user.getRoles().add(role);
            userOptional = Optional.of(userRepository.save(user));
        }
        return new CustomOidcUser(oidcUser, userOptional.get().getRoles());
    }


}
© www.soinside.com 2019 - 2024. All rights reserved.