Spring Security 3.x.x - FilterChain不工作,但@PreAuthorize只工作

o3imoua4  于 9个月前  发布在  Spring
关注(0)|答案(1)|浏览(72)
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    private final LoginService loginService;
    private final JwtService jwtService;
    private final AdminRepository adminRepository;
    private final ObjectMapper objectMapper;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(cs -> cs.disable())
                .sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .formLogin(f->f.disable())
                .httpBasic(h->h.disable());
        http
                .authorizeHttpRequests(auth->{
////                    auth.requestMatchers("/lectures/**").hasAnyRole("MANAGER")
////                    auth.requestMatchers("/instructors/**").hasAnyRole("MANAGER")
//                    auth.requestMatchers("/instructors/**").authenticated()
//                                    .requestMatchers("/lectures/**").permitAll()
////                        .requestMatchers("/instructors/**").hasAnyRole("MANAGER")
//                            .requestMatchers("/admins/**").permitAll()
//                            .requestMatchers("/login").permitAll()
//auth.requestMatchers("/instructors/**").hasRole("MANAGER")
                    auth.anyRequest().permitAll()

                    ;
                });
        return http.build();
    }
    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        provider.setUserDetailsService(loginService);
        return new ProviderManager(provider);
    }

    @Bean
    public LoginSuccessHandler loginSuccessHandler() {
        return new LoginSuccessHandler(jwtService, adminRepository);
    }

    @Bean
    public LoginFailureHandler loginFailureHandler() {
        return new LoginFailureHandler();
    }

    @Bean
    public CustomJsonUsernamePasswordAuthenticationFilter customJsonUsernamePasswordAuthenticationFilter() {
        CustomJsonUsernamePasswordAuthenticationFilter customJsonUsernamePasswordLoginFilter
                = new CustomJsonUsernamePasswordAuthenticationFilter(objectMapper);
        customJsonUsernamePasswordLoginFilter.setAuthenticationManager(authenticationManager());
        customJsonUsernamePasswordLoginFilter.setAuthenticationSuccessHandler(loginSuccessHandler());
        customJsonUsernamePasswordLoginFilter.setAuthenticationFailureHandler(loginFailureHandler());
        return customJsonUsernamePasswordLoginFilter;
    }

    @Bean
    public JwtAuthenticationProcessingFilter jwtAuthenticationProcessingFilter() {
        JwtAuthenticationProcessingFilter jwtAuthenticationFilter = new JwtAuthenticationProcessingFilter(jwtService, adminRepository);
        return jwtAuthenticationFilter;
    }
}

x

@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationProcessingFilter extends OncePerRequestFilter {

    private static final String NO_CHECK_URL = "/login";

    private final JwtService jwtService;
    private final AdminRepository adminRepository;

    private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().equals(NO_CHECK_URL)) {
            filterChain.doFilter(request, response);
            return;
        }

        String refreshToken = jwtService.extractRefreshToken(request)
                .filter(jwtService::isTokenValid)
                .orElse(null);

        if (refreshToken != null) {
            checkRefreshTokenAndReIssueAccessToken(response, refreshToken);
            return;
        }

        if (refreshToken == null) {
            checkAccessTokenAndAuthentication(request, response, filterChain);
        }
    }

    public void checkRefreshTokenAndReIssueAccessToken(HttpServletResponse response, String refreshToken) {
        adminRepository.findByRefreshToken(refreshToken)
                .ifPresent(admin -> {
                    String reIssuedRefreshToken = reIssueRefreshToken(admin);
                    jwtService.sendAccessAndRefreshToken(response, jwtService.createAccessToken(admin.getEmail()),
                            reIssuedRefreshToken);
                });
    }

    private String reIssueRefreshToken(Admin admin) {
        String reIssuedRefreshToken = jwtService.createRefreshToken();
        admin.updateRefreshToken(reIssuedRefreshToken);
        adminRepository.saveAndFlush(admin);
        return reIssuedRefreshToken;
    }

    public void checkAccessTokenAndAuthentication(HttpServletRequest request, HttpServletResponse response,
                                                  FilterChain filterChain) throws ServletException, IOException {
        log.info("checkAccessTokenAndAuthentication() 호출");
        jwtService.extractAccessToken(request)
                .filter(jwtService::isTokenValid)
                .ifPresent(accessToken -> jwtService.extractEmail(accessToken)
                        .ifPresent(email -> adminRepository.findByEmail(email)
                                .ifPresent(this::saveAuthentication)));
        log.info("saveAuthentication() 호출");
        filterChain.doFilter(request, response);
    }

    public void saveAuthentication(Admin myAdmin) {
        String password = myAdmin.getPassword();

        UserDetails userDetailsUser = org.springframework.security.core.userdetails.User.builder()
                .username(myAdmin.getEmail())
                .password(password)
                .roles(myAdmin.getRole().name())
                .build();

        Authentication authentication =
                new UsernamePasswordAuthenticationToken(userDetailsUser, null,
                        authoritiesMapper.mapAuthorities(userDetailsUser.getAuthorities()));

        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}
@RequiredArgsConstructor
@RequestMapping("/instructors")
@RestController
public class InstructorController {

    private final InstructorService instructorService;

    @PostMapping
    @PreAuthorize("hasRole('ROLE_MANAGER')")//it works
    public ResponseEntity createInstructor(@Valid @RequestBody InstructorPostDto instructorPostDto) {
        InstructorResponseDto createdInstructor = instructorService.createInstructor(instructorPostDto);
        return new ResponseEntity<>(createdInstructor, HttpStatus.CREATED);
    }
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.7'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.hh99'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    // security 관련 의존성
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    // jwt 관련 의존성
    implementation 'com.auth0:java-jwt:4.2.1'
}

tasks.named('bootBuildImage') {
    builder = 'paketobuildpacks/builder-jammy-base:latest'
}

tasks.named('test') {
    useJUnitPlatform()
}

的数据
嗨,我正试图在我的小应用程序上应用Spring Security+JWT,我希望只有'BERGER'可以访问/lectures,/instructions,但即使用户有BERGER授权,他们也无法访问它们,所以我将hasAnyRole(“BERGER”)更改为BERGER All()并在Controller上应用@PreAuthorized,然后它可能会工作过滤器的顺序或只是代码问题。

nhaq1z21

nhaq1z211#

有两种方法可以解决这个问题
1.您可以使用hasAuthority而不是hasRole
第一个月
1.权限应该在role前面加上“ROLE_"。您可以修改实体类中的getAuthorities()方法,扩展org.springframework.security.core.userdetails.UserDetails类,如下所示

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return List.of(new SimpleGrantedAuthority("ROLE_"+role.name()));
}

字符串
difference-between-role-and-grantedauthority-in-spring-security这里是详细解释这个概念的链接。

相关问题