Spring Boot Spring Security permitAll()不适用于匿名[空身份验证]

9nvpjoqh  于 2022-11-05  发布在  Spring
关注(0)|答案(2)|浏览(179)

所以我尝试使用JWT实现一个注册和登录机制。但是,尽管在安全配置中使用了permitAll(),但当未经身份验证的用户尝试访问“/user/register”时,它仍然返回401
这里是UserServiceImpl.java

package com.kelompok7.bukuku.user;

import com.kelompok7.bukuku.user.role.ERole;
import com.kelompok7.bukuku.user.role.Role;
import com.kelompok7.bukuku.user.verificationToken.VerificationToken;
import com.kelompok7.bukuku.user.verificationToken.VerificationTokenRepo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service @RequiredArgsConstructor @Transactional @Slf4j
public class UserServiceImpl implements UserService, UserDetailsService {
@Autowired
private final UserRepo userRepo;
@Autowired
private final VerificationTokenRepo verificationTokenRepo;
@Autowired
private JavaMailSender mailSender;

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepo.findByUsername(username);
        if(user == null){
            log.error("{}", SecurityContextHolder.getContext().toString());
            log.error("User not found in the database");
            throw new UsernameNotFoundException("User not found in the database");
        }
        else{
            log.info("User found in the database: {}", username);
        }
        Collection<SimpleGrantedAuthority> authorities = user.getAuthorities();
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
    }

    @Override
    public User register(User user) throws MessagingException, UnsupportedEncodingException {
        log.info("Saving new user {} to the database", user.getName());
        user.setPassword(encoder().encode(user.getPassword()));
        Set<Role> role = new HashSet<>();
        role.add(new Role(ERole.ROLE_USER));
        user.setRoles(role);
        user.setEnabled(false);
        userRepo.save(user);
        return user;
    }

}

这里是UserController.java

package com.kelompok7.bukuku.user;

import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.query.Param;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.\*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.mail.MessagingException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;

    @PostMapping("/register")
    public ResponseEntity<User> register(@RequestBody User user) throws MessagingException, UnsupportedEncodingException {
        URI uri = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("user/register").toUriString());
        return ResponseEntity.created(uri).body(userService.register(user));
    }
}

这里是SecurityConfiguration.java

package com.kelompok7.bukuku.security;

import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    @Autowired
    private final RsaKeyProperties rsaKeys;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .csrf(csrf -> csrf.disable())
                .cors(cors -> cors.disable())
                .authorizeRequests(auth -> auth
                        .antMatchers("/**").permitAll()
                        .anyRequest().permitAll()
                )
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .httpBasic(Customizer.withDefaults())
                .build();
    }

//    @Bean
//    public WebSecurityCustomizer webSecurityCustomizer() {
//        return (web) -\> web.ignoring()
//                .antMatchers("/\*\*");
//    }

    @Bean
    JwtDecoder jwtDecoder(){
        return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
    }

    @Bean
    JwtEncoder jwtEncoder(){
        JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
        JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwks);
    }

}

最后是日志

2022-11-03 16:15:29.525 ERROR 19358 --- [nio-8081-exec-2] c.kelompok7.bukuku.user.UserServiceImpl  : SecurityContextImpl [Null authentication]
2022-11-03 16:15:29.525 ERROR 19358 --- [nio-8081-exec-2] c.kelompok7.bukuku.user.UserServiceImpl  : User not found in the database

我希望请求会通过并被处理,但它似乎被SecurityFilterChain捕获并得到401 Unauthorized。我尝试禁用CSRF和CORS,但仍然失败。我甚至刚刚将permitAll()设置为anyRequest,但不知何故仍然得到401。

唯一可行的方法似乎是使用webSecurityCustomizer和web.ignoring(),但我读到它将完全跳过securityFilterChain,所以我不确定它是否安全。它安全吗?它通常是这样做的吗?有没有更好的方法?

另外,即使web.ignoring()有效,我也想知道为什么permitAll()不起作用。这是正常的吗?
谢谢你的回答

hec6srdp

hec6srdp1#

您是否尝试过在antmatcher中提供完整路径

.antMatchers("user/register).permitAll()

2ekbmq32

2ekbmq322#

我真的很抱歉,但事实证明,这是由于我的愚蠢的错误,包括授权在请求时,我不应该。
我最初的要求是:

POST /user/register HTTP/1.1
Host: localhost:8080
Authorization: Basic dXNlcjpwYXNzd29yZA==
Content-Type: application/json
Content-Length: 100

{
    "username": "user",
    "password": "password",
    "email": "email@mail.com"
}

它应该是什么,以及工作:

POST /user/register HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 100

{
    "username": "user",
    "password": "password",
    "email": "email@mail.com"
}

getContext()仍然返回空的身份验证,但permitAll()工作正常,所以我猜这是正常的行为。这整个时间我怀疑这是不是原因,所以我花了很多天试图解决它没有用。
我很感激你的帮助谢谢。

相关问题