首页 > 解决方案 > SpringBoot:Imp SpringSecurity:使用用户/密码登录时出现屏幕错误消息“用户已禁用”

问题描述

我刚刚开始实施 SpringSecurity 但登录后在屏幕上收到错误消息“用户已禁用”

默认情况下它工作得很好。在使用 /user 或 /admin 并尝试登录时显示“用户已禁用”

我正在执行以下步骤:

  1. 首先创建 schema.sql(在资源文件夹下)

    CREATE TABLE USERS (
        USERNAME VARCHAR(128) PRIMARY KEY,
        PASSWORD VARCHAR(128) NOT NULL,
        ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL
    );
    
    CREATE TABLE AUTHORITIES (
        USERNAME VARCHAR(128) NOT NULL,
        AUTHORITY VARCHAR(128) NOT NULL
    );
    
    ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY);
    ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME);
    
  2. 在资源文件夹下创建“data.sql”

    insert into USERS(USERNAME,PASSWORD,ENABLED) VALUES ('user','pass','Y');
    insert into USERS(USERNAME,PASSWORD,ENABLED) VALUES ('admin','pass','Y');
    insert into AUTHORITIES (USERNAME,AUTHORITY) values ('user','ROLE_USER');
    insert into AUTHORITIES (USERNAME,AUTHORITY) values ('admin','ROLE_ADMIN');
    
  3. HomeResource.JAVA(这是一个控制器类 API)

    package com.example.callCenter;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HomeResource{
    
        @GetMapping("/")
        public String home(){
            return("<h1>Welcome home page..</h1>");
        }
    
        @GetMapping("/user")
        public String user()
        {
            return ("<h1>Welcome User page</h1>");
        }
    
        @GetMapping("/admin")
        public String admin()
        {
            return("<h1>Welcome Admin page</h1>");
        }
    }
    
  4. SecurityConfiguration.java(这是启用 Spring Form PAGE)

    package com.example.callCenter;
    
    import javax.sql.DataSource;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    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.User;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        DataSource dataSource;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select username,password,enabled "
                            + "from users "
                            + "where username = ?")
                .authoritiesByUsernameQuery("select username,AUTHORITY  "
                            + "from AUTHORITIES "
                            + "where username = ?");
    
            // This beloe code is default implementation with MySQL database
            // auth.jdbcAuthentication()
            //         .dataSource(dataSource)
            //         .withDefaultSchema()
            //         .withUser( 
            //                     User.withUsername("user")
            //                     .password("pass")
            //                     .roles("USER")
    
            //         )
            //         .withUser( 
            //                     User.withUsername("admin")
            //                     .password("pass")
            //                     .roles("ADMIN")
            //         );
    
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                .authorizeRequests()
                    .antMatchers("/admin").hasRole("ADMIN")
                    .antMatchers("/user").hasAnyRole("ADMIN","USER")
                    .antMatchers("/").permitAll()
                    .and().formLogin();
        }
    
        @Bean
        public PasswordEncoder getPasswordEncoder()
        {
            return NoOpPasswordEncoder.getInstance();
        }
    
    }
    
  5. 调用应用程序.java

    package com.example.callCenter;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class CallApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CallCenterApplication.class, args);
        }
    
    }
    

    pom.xml :由于表单正在打开,因此所有依赖项都不是问题

    应用程序属性:

    spring.datasource.url=
    spring.datasource.username=
    spring.datasource.password=
    spring.datasource.driverClassName=
    
    spring.jpa.show_sql=true
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
    spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
    spring.jpa.format_sql=true
    

我添加了几乎所有细节,我这边没有任何待处理的内容,但现在我需要一些帮助,为什么它不允许我打电话给用户并允许我登录。

标签: springspring-bootspring-security

解决方案


这里的问题是存储在列中的值

ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL

JdbcUserDetailsManager。loadUsersByUsername(String username)在创建 User 对象时具有以下代码逻辑来填充其属性。

                String userName = rs.getString(1);
                String password = rs.getString(2);
                boolean enabled = rs.getBoolean(3);

要获得enabled状态, 使用ResultSet.getBoolean()并且相同的 java 文档提到以下内容

检索此 ResultSet 对象的当前行中指定列的值,作为 Java 编程语言中的布尔值。

如果指定列的数据类型为 CHAR 或 VARCHAR 且包含“0”,或者数据类型为 BIT、TINYINT、SMALLINT、INTEGER 或 BIGINT 且包含 0,则返回 false 值。如果指定列的数据类型为 CHAR 或 VARCHAR 且包含“1”,或者数据类型为 BIT、TINYINT、SMALLINT、INTEGER 或 BIGINT 且包含 1,则返回值 true。

在上面的代码中,启用/禁用的正确值分别是“1”和“0”。


推荐阅读