[SpringBoot2.4.3] DB認証によるログイン処理を実装したい

WebSecurityConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.example.demo;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
 
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
     
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/resources/**");
    }
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .successForwardUrl("/home")
                .failureUrl("/login?error")
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .permitAll()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }
}

DemoController.java
L UserModelは後から作ります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.demo;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.security.core.Authentication;
 
@Controller
public class DemoController {
    @RequestMapping(value = {"/", "/home"})
    public String home() {
        return "home";
    }
     
    @RequestMapping(value = "/hello")
    public String hello(Authentication authentication, Model model) {
        UserModel userModel = (UserModel)authentication.getPrincipal();
        model.addAttribute("name", userModel.getUsername());
         
        return "hello";
    }
}

pom.xml
L jdbcとpostgres追加

1
2
3
4
5
6
7
8
9
10
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
 
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>

application.properties
L jdbc, postgres追加

1
2
3
4
spring.jpa.database=POSTGRESQL
spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.datasource.username=root
spring.datasource.password=

$ psql -U root test
test=> \d

1
2
3
4
5
6
7
8
9
10
11
12
create table t_user (
    id serial primary key,
    name varchar(255),
    password varchar(255),
    enabled boolean DEFAULT true
);
 
insert into t_user (name, password) values
('user1','password'),
('user2','password');
 
select * from t_user;

UserModel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example.demo;
 
import java.util.Collection;
 
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.GrantedAuthority;
 
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserModel implements UserDetails{
 
    private String id;
    private String name;
    private String password;
    private boolean enabled;
     
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities(){
        return null;
    }
     
    @Override
    public String getPassword() {
        return this.password;
    }
     
    @Override
    public String getUsername() {
        return this.name;
    }
     
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
     
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
     
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
     
    @Override
    public boolean isEnabled() {
        return this.enabled;
    }
}

UserRepository.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserRepository">
    <select id="selectByUser" parameterType="com.example.demo.UserRepository" resultType="com.example.demo.UserModel">
        SELECT id, name, password, enabled FROM t_user where id = #{id};
    </select>
</mapper>

UserRepository.java

1
2
3
4
5
6
7
8
package com.example.demo;
 
import org.apache.ibatis.annotations.Mapper;
 
@Mapper
public interface UserRepository {
    public UserModel selectByUser(String username);
}

UserDetailsServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.example.demo;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
     
    @Autowired
    private UserRepository userRepository;
     
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(StringUtils.isEmpty(username)) throw new UsernameNotFoundException("");
         
        UserModel userModel = userRepository.selectByUser(username);
         
        if(userModel == null) throw new UsernameNotFoundException("");
        if(!userModel.isAccountNonExpired() || !userModel.isAccountNonLocked() ||
                !userModel.isCredentialsNonExpired() || !userModel.isEnabled())
            throw new UsernameNotFoundException("");
        return userModel;
    }
 
}

Description:

Field userRepository in com.example.demo.UserDetailsServiceImpl required a bean of type ‘com.example.demo.UserRepository’ that could not be found.

なんでや。。。なんでや。。。。
もう一回やるか、次ラストで。