spring-security Spring Security为注册用户返回401

7ivaypg9  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(173)

我尝试构建一个简单的Spring Security应用程序,该应用程序注册用户,并具有1个端点,该端点应可供已验证用户使用。注册成功,但当我尝试使用已注册用户的基本身份验证访问/auth EP时,我得到401未授权。
例如,我用以下公式计算POST /register

{
    "name":"John",
    "lastname":"Doe",
    "email":"john@acme.com",
    "password":"123"
}

然后调用GET /auth
用户名:john@acme.com
密码:123
我得到401
使用硬编码用户调用时:
用户名:admin
密码:123
我得到200

控制器

package com.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@Validated
public class AccountServiceController {

    UserService userService;
    @Autowired
    public AccountServiceController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/register")
    public ResponseEntity register(@RequestBody @Valid UserDTO user) {
        return new ResponseEntity(userService.saveUser(user), HttpStatus.OK);
    }

    @GetMapping("/auth")
    public String getAuth() {
        return "Access granted";
    }

}

用户实体

package com.AccountService;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.autoconfigure.domain.EntityScan;

import javax.persistence.*;

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    private String lastname;
    private String email;
    private String password;

    public UserEntity(String name, String lastname, String email, String password) {
        this.name = name;
        this.lastname = lastname;
        this.email = email;
        this.password = password;
    }

}

用户DTO

package com.AccountService;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {

    private String name;
    private String lastname;
    @Pattern(regexp = "[a-zA-Z0-9.-]+@acme.com",message = "Wrong email")
    private String email;
    @NotEmpty
//    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;

}

用户存储库

package com.AccountService;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {

    @Query("select u from UserEntity u where upper(u.email) = upper(?1)")
    UserEntity findByEmailIgnoreCase(String email);

}

用户服务

package com.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class UserService {

    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    UserRepository userRepository;

    public Map<String, String> saveUser(UserDTO userDTO) {
        userDTO.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        UserEntity newUser = new UserEntity(
                userDTO.getName(),
                userDTO.getLastname(),
                userDTO.getEmail(),
                userDTO.getPassword()
        );
        userRepository.save(newUser);
        return Map.of(
                "id", String.valueOf(newUser.getId()),
                "name", newUser.getName(),
                "lastName", newUser.getLastname(),
                "email", newUser.getEmail());
    }

}

用户详细信息实施

package com.AccountService;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.Set;

public class UserDetailsImpl implements UserDetails {

    private final String username;
    private final String password;

    public UserDetailsImpl(String username, String password) {
        this.username = username;
        this.password = password;
    }

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

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}

用户详细信息服务

package com.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
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;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    UserRepository userRepository;

    @Autowired
    public UserDetailsServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity user = userRepository.findByEmailIgnoreCase(username);
        if (user == null) {
            throw new UsernameNotFoundException("No user found with email" + username);
        }
        return new UserDetailsImpl(user.getEmail(),user.getPassword());
    }
}

安全配置

package com.AccountService;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@Configuration
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    UserDetailsServiceImpl userDetailsService;
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .httpBasic()
                .and()
                .authorizeRequests()
                .mvcMatchers("/auth").authenticated()
                .mvcMatchers("/register").permitAll()
                .and()
                .csrf().disable()
                .headers().frameOptions().disable();
    }

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {

        builder.userDetailsService(userDetailsService)
                .passwordEncoder(getEncoder());
        builder
                .inMemoryAuthentication()
                .withUser("admin").password("123").roles()
                .and().passwordEncoder(NoOpPasswordEncoder.getInstance());
    }
    @Bean
    public PasswordEncoder getEncoder() {
        return new BCryptPasswordEncoder();
    }
}

应用程序.属性

server.error.include-message=always

management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
spring.jackson.serialization.INDENT_OUTPUT=true

spring.datasource.url=jdbc:h2:file:../service_db
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update

spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false

spring.jpa.show-sql=true

构建.gradle

plugins {
    id 'org.springframework.boot' version '2.7.3'
    id 'io.spring.dependency-management' version '1.0.13.RELEASE'
    id 'java'
}

group = 'com'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = "1.9"

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'junit:junit:4.13.1'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'com.unboundid:unboundid-ldapsdk'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.7.3'
    testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.0'
    implementation 'org.springframework.boot:spring-boot-starter-security:2.7.3'
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    implementation group: 'org.hibernate', name: 'hibernate-validator', version: '6.1.0.Final'

}

tasks.named('test') {
    useJUnitPlatform()
}
test {
    useJUnitPlatform()
}
targetCompatibility = JavaVersion.VERSION_1_9
mzsu5hc0

mzsu5hc01#

[已解决]

UserDetailsImpl中的布尔方法被设置为false,导致用户被锁定。必须更改为return true;
谢谢,@M.代努姆

相关问题