【问题标题】:Spring Boot: How to specify the PasswordEncoder?Spring Boot:如何指定 PasswordEncoder?
【发布时间】:2018-04-10 12:41:42
【问题描述】:

目前我得到了主课:

package com.recweb.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
/*@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})*/
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

一个成员类(id, firstname..),一个 MemberController 类:

package com.recweb.springboot;

import java.util.Arrays;
import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemberController {
    @GetMapping("/members")
    public List<Member> getAllUsers() {
        return Arrays.asList(new Member(1, "amit"));
    }
}

还有一个 WebSecurityConfig 类:

package com.recweb.springboot;

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("user").roles("USER").build());
        return manager;
    }
}

当我运行“http://localhost:8080/members”时,我得到一个登录页面,我输入“user”作为用户和“user”作为密码,然后我得到硬编码的成员。 它工作得很好,但是然后我右键单击了我的项目-Run as-Maven 安装(因为我添加了一个依赖项,我不知道这是否有必要,也是第一次使用 Maven)。 从那时起,当我在登录页面上输入“用户”和“用户”时,我收到此错误:

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
    at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:86) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) ~[spring-security-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.1.RELEASE.jar:5.0.1.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.23.jar:8.5.23]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]

它停留在登录页面上。 我试图再次删除依赖项和 Maven 安装,但没有运气。 这是我的 POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.recweb</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.BUILD-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</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-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
                </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.3.0.Final</version>
</dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
<!--         <scope>provided</scope> -->
</dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


</project>

出了什么问题? 谢谢

【问题讨论】:

  • 最后一次尝试。转到您的文件夹C:\Users\USER\.m2\repository 并将其删除。回到日食。 Maven clean -> 作为 Java 应用程序运行。
  • 为什么要使用 SNAPSHOT 依赖项?

标签: spring maven spring-boot spring-security


【解决方案1】:

spring-security-core:5.0.0.RC1 中,默认PasswordEncoder 构建为DelegatingPasswordEncoder。当您将用户存储在内存中时,您以纯文本形式提供密码,并且在尝试从DelegatingPasswordEncoder 检索编码器以验证密码时,它找不到与这些密码存储方式匹配的密码。

改用这种方式创建用户。

User.withDefaultPasswordEncoder().username("user").password("user").roles("USER").build(); 

您也可以简单地将{noop} 添加到您的密码前,以便DelegatingPasswordEncoder 使用NoOpPasswordEncoder 来验证这些密码。请注意,NoOpPasswordEncoder 已被弃用,因为以纯文本形式存储密码不是一个好习惯。

User.withUsername("user").password("{noop}user").roles("USER").build();

有关更多信息,请查看此帖子。

https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-encoding

【讨论】:

  • 谢谢,这对我也适用于 XML,
  • withDefaultPasswordEncoder 已被弃用。有人知道建议的替代方案是什么吗?
  • @zero01alpha 已被弃用,原因与 NoOpPasswordEncoder 相同,它对生产不安全。 Spring 期望您仅将其用于示例应用程序。对于生产,这应该被外部化。
【解决方案2】:

NoOpPasswordEncoder 用于inMemoryAuthentication

auth.inMemoryAuthentication()
    .withUser("user")
    .password("{noop}password")
    .roles("USER")

【讨论】:

  • 可以,但是使用 NoOpPasswordEncoder 密码不安全。
  • 本例中auth是什么对象类型?
  • @Michael 它是一个 AuthenticationManagerBuilder 来自 WebSecurityConfigurerAdapter 的配置器方法
【解决方案3】:

你需要某种密码编码器,但是

withDefaultPasswordEncoder()

已弃用,不再适合生产。改用这个:

PasswordEncoder encoder =
     PasswordEncoderFactories.createDelegatingPasswordEncoder();

...

UserDetails user = User.withUsername("someusername")
                       .password(encoder.encode("somepassword"))
                       .roles("USER").build();

参考:https://docs.spring.io/spring-security/site/docs/5.0.2.BUILD-SNAPSHOT/api/index.html?org/springframework/security/core/userdetails/User.html

【讨论】:

  • 这应该被接受,因为它确实回答了问题
【解决方案4】:

我只是添加了

 @Bean
public static NoOpPasswordEncoder passwordEncoder() {
 return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}

到配置类

【讨论】:

    【解决方案5】:
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception{    
        auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance())
                .withUser("test").password("test123").roles("USER").and()
                .withUser("test1").password("test123").roles("ADMIN");
    }
    

    【讨论】:

      【解决方案6】:

      SecurityConfig extends WebSecurityConfigurerAdapter 试试这个:

      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();
      }
      @Override
      protected void configure(final AuthenticationManagerBuilder auth) throws Exception{        
          auth
              .inMemoryAuthentication()
                  .withUser("user")
                  .password(passwordEncoder().encode("password"))
                  .roles("USER")
              .and()
                  .withUser("admin")
                  .password(passwordEncoder().encode("admin"))
                  .roles("USER", "ADMIN");
      }
      

      为我工作

      【讨论】:

        【解决方案7】:

        您可以使用它,但请注意User.withDefaultPasswordEncoder()弃用

        @Bean
        @Override
        public UserDetailsService userDetailsService() {
        
            PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        
            final User.UserBuilder userBuilder = User.builder().passwordEncoder(encoder::encode);
            UserDetails user = userBuilder
                    .username("user")
                    .password("password")
                    .roles("USER")
                    .build();
        
            UserDetails admin = userBuilder
                    .username("admin")
                    .password("password")
                    .roles("USER","ADMIN")
                    .build();
        
            return new InMemoryUserDetailsManager(user, admin);
        }
        

        【讨论】:

          【解决方案8】:

          使用以下任何一种都可以正常工作:-

          @Autowired
              public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
                  auth.inMemoryAuthentication().withUser("admin").password("{noop}admin@123").roles("admin");
              }
          

          @Override
              protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  auth.inMemoryAuthentication().withUser("admin").password("{noop}admin").roles("admin");
              }
          

          @Override
              protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("{noop}admin").roles("admin");
              }
          

          谢谢!

          【讨论】:

            【解决方案9】:

            您需要像这样设置密码编码器:

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

            在 Spring Boot 2 中,用户和客户端都需要使用 passwordEncoder

            查看此存储库https://github.com/dzinot/spring-boot-2-oauth2-authorization-jwt

            您可以看到 passwordEncoder 是如何设置的,以及如何与数据库中的用户和客户端一起使用它。

            【讨论】:

              【解决方案10】:

              在所有现有密码前加上 {noop} 以保留 Spring Security 5 的默认编码器。

              例子:

              auth.inMemoryAuthentication()
                  .withUser("admin").password("{noop}admin!234").roles("ADMIN");
              

              【讨论】:

                【解决方案11】:

                根据spring security 5.0 's new feature. 他们写this

                Spring Security 的 PasswordEncoder 接口用于执行一个 密码的方式转换以允许存储密码 安全地。鉴于 PasswordEncoder 是一种单向转换,它不是 当密码转换需要两种方式时(即 存储用于对数据库进行身份验证的凭据)。通常 PasswordEncoder 用于存储需要输入的密码 与验证时用户提供的密码相比。

                所以我尝试了这个Mutiple HttpSecurity。 这是我的安全配置。希望对你有帮助。

                @Configuration
                @EnableWebSecurity
                public class SecurityConfig
                {
                  private final EdminService edminService;
                  public SecurityConfig ( final EdminService edminService ){
                    this.edminService=edminService;
                  }
                  @Bean
                  public UserDetailsService userDetailsService() throw Exception {
                    UserBuilder users= Users.withDefaultPasswordEncoder;
                    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
                    List<EdminEntity> edminList=this.edminService.findAll();
                    for(EdminEntity edmin: edminList){
                     manager.createUser(users.username(edmin.getEdminname())
                     .password(edmin.getEdminrpass()).roles("EDMIN_ROLE").build());
                    }
                    return manager;
                  }
                  @Configuration
                  @Order(1)
                  public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
                    protected void configure(HttpSecurity http) throws Exception {
                       http
                       .authorizeRequests()
                       .antMatchers("/home","/vendor/**","/image/**","/home/**").permitAll()
                       .antMatchers("/admin/**").hasRole("EDMIN_ROLE")
                       .anyRequest().authenticated()
                       .and()
                       .formLogin()
                       .loginPage("/login")
                       .permitAll()
                       .defaultSuccessUrl("/home")
                       .and()
                       .logout()
                       .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));}
                   }
                }
                

                对不起我的英语并感谢您阅读我的回答。

                【讨论】:

                  【解决方案12】:
                  A few days ago I have to face the same problem on spring security version (5.0.8). See the example version here:
                  
                  code:
                  
                  @Override
                      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                  
                  auth
                                  .inMemoryAuthentication()
                                  .passwordEncoder(NoOpPasswordEncoder.getInstance())
                                  .withUser("farid").password("farid").roles("USER")
                                  .and()
                                  .withUser("admin").password("admin").roles("ADMIN");
                      }
                  
                  OR
                  
                  When you are configuring the ClientDetailsServiceConfigurer, you have to also apply the new password storag`enter code here`e format to the client secret.
                  
                  .secret("{noop}secret")
                  

                  你可以看到链接:enter link description here

                  【讨论】:

                    【解决方案13】:

                    您需要设置密码编码器,请查看以下示例

                    PasswordEncoder encoder =
                                 PasswordEncoderFactories.createDelegatingPasswordEncoder();
                        auth.inMemoryAuthentication().passwordEncoder(encoder).withUser("Ahmad")
                                .password("1600").roles("USER", "ADMIN").and().withUser("Belal").password("1515").roles("USER");
                    

                    【讨论】:

                      【解决方案14】:

                      在我的初始应用程序加载启动管家中有IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" 异常。 (只需要在应用程序启动之前规范化数据库中的数据。)使用this (manually set an authenticated user) 方法,您可以创建UsernamePasswordAuthenticationToken 和setAuthentication。如果您没有指定第三个参数AuthorityList,您可能会得到 IllegalArgumentException。

                      UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
                              admin.getEmail(), 
                              UserServiceImpl.PASSWORD_ENCODER.encode(admin.getPassword()),
                              AuthorityUtils.createAuthorityList(admin.getRoles()) // <= had to add this line to resolve the exception
                      );
                      
                      SecurityContextHolder.getContext().setAuthentication(authReq);
                      

                      也许其他一些设置步骤也可以,但设置 AuthorityList 对我来说已经足够了。如果在此页面上找不到解决方案,您至少可以朝这个方向挖掘。

                      【讨论】:

                        【解决方案15】:

                        如果您正在使用内存身份验证,这里是有关如何进行的代码。在 Spring Boot 2.3.3.RELEASE 上测试

                        @Configuration
                        @EnableWebSecurity
                        public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                            static PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
                        
                            @Override
                            protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                                auth.inMemoryAuthentication().withUser("testuser").password(encoder.encode("testpassword")).roles("ADMIN");
                            }
                        
                            @Override
                            protected void configure(HttpSecurity http) throws Exception {
                                http.csrf().disable();
                                http.authorizeRequests().antMatchers("/sites.xhtml/**").hasRole("ADMIN").anyRequest().fullyAuthenticated().and()
                                        .httpBasic();
                            }
                        
                            @Bean
                            public static PasswordEncoder passwordEncoder() {
                                return encoder;
                        
                            }
                        }
                            
                        

                        【讨论】:

                          【解决方案16】:

                          由于我发现这个问题有很多不同的赞成答案,但几乎没有什么解释,我决定提供我自己的答案,这应该可以更深入地了解 Spring Security 密码编码的工作原理。我花了一些时间调试 Spring 代码以找出所有细节。

                          在内部,Spring Security 在对用户进行身份验证时使用DelegatingPasswordEncoder。假设在登录期间提供了凭据user:passwordDelegatingPasswordEncoder 会加载此特定用户的存储密码并尝试确定其编码。 DelegatingPasswordEncoder 期望密码以{type}hash 的形式存储:

                          {bcrypt}hash
                          {scrypt}hash
                          {MD5}hash
                          {noop}hash
                          ...
                          

                          如果默认DelegatingPasswordEncoder 现在遇到没有{type} 的存储密码,它无法推断要使用哪个编码器,而是使用引发异常的UnmappedIdPasswordEncoder。这意味着发生异常是因为密码存储时没有任何编码信息,而 Spring Security 使用了无法处理的DelegatingPasswordEncoder

                          解决此问题的一种方法是同时使用DelegatingPasswordEncoder 对密码进行编码和存储。使用PasswordEncoderFactories.createDelegatingPasswordEncoder() 检索的编码器将使用bcrypt 作为默认编码,因此密码将存储为{bcrypt}hash

                          @Override
                          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                          
                              PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
                          
                              auth.inMemoryAuthentication()
                                  .withUser("user")
                                  .password(encoder.encode("password"))
                                  .roles("USER");
                          }
                          

                          当您想在项目中处理不同的编码时,DelegatingPasswordEncoder 很有用。例如,假设旧密码以纯文本形式存储,而新密码现在使用bcrypt 编码。您只需在所有旧存储密码前加上 {noop} 即可,一切顺利。如果你存储了用 MD5 编码的密码,它的工作原理是一样的,只需在它们前面加上 {MD5}

                          在一个新项目中,也可以定义一个特定的编码,比如BCryptPasswordEncoder,而不是使用委托编码。当编码器注册为 bean 时,Spring Security 也会使用这个编码器进行身份验证,而不是 DelegatingPasswordEncoder。密码现在存储为bcrypt hash,没有{type}

                          @Bean
                          public PasswordEncoder passwordEncoder() {
                              return new BCryptPasswordEncoder();
                          }
                          
                          @Override
                          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                          
                              auth.inMemoryAuthentication()
                                  .withUser("user")
                                  .password(passwordEncoder().encode("password"))
                                  .roles("USER");
                          }
                          

                          因此,您可以选择所描述的变体之一。我最近选择了PasswordEncoderFactories.createDelegatingPasswordEncoder(),因为这只需要一行代码,并且不需要创建 bean。

                          【讨论】:

                            【解决方案17】:

                            我就是这样解决的

                                @Bean
                                public PasswordEncoder delegatingPasswordEncoder() {
                                    Map<String, PasswordEncoder> encoders = new HashMap<>();
                                    encoders.put("bcrypt", new BCryptPasswordEncoder());
                                    DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders);
                                    passwordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
                                    return passwordEncoder;
                                }
                            

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2022-10-25
                              • 2013-06-30
                              • 2014-05-26
                              • 2016-07-10
                              • 2023-02-21
                              相关资源
                              最近更新 更多