Home > AI > Backend > SpringBoot > spring-boot-starter-security >

Spring Security use Mysql as datasource

Dependencies

pom.xml

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</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>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.properties


server.port = 8888


##################
# Mysql
##################
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.show-sql= false

Firstly, we need to understand ManyToMany relationship in MySQL how to do CRUD operations.

Since User and Role are ManyToMany relationship

User.java

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "users")
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    private Long id;


    @Column(name = "username")
    private String username;


    @Column(name = "email")
    private String email;


    @Column(name = "password")
    private String password;


    @Column(name = "name")
    private String name;


    @Column(name = "lastName")
    private String lastName;


    @Column(name = "enabled")
    private Boolean enabled = true;


    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "user_role",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();


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


    public void addRole(Role role) {
        this.roles.add(role);
        role.getUsers().add(this);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        System.out.println("[Shark]" + roles);


        List<SimpleGrantedAuthority> rs = new ArrayList<>();



        for (Role r : roles) {
            rs.add(new SimpleGrantedAuthority(r.getName()));
        }

        return rs;
    }

    @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;
    }
}

Role.java

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "roles")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_id")
    private Long id;

    @Column(name = "name")
    private String name;


    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
    private Set<User> users = new HashSet<>();

    public Role(String name) {
        this.name = name;
    }
}

UserRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByEmail(String email);
    User findByUsername(String username);
}

RoleRepository.java

@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
    Role findByName(String name);
}

MyUserDetailsService.java

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("[Shark] " + username);

        User u = userRepository.findByUsername(username);

        System.out.println("[Shark] " + u.getRoles());


        if (u == null ){
            throw  new UsernameNotFoundException("cannot find the user");
        } else {
            return u;
        }
    }
}

DataInitListener.java

@Component
public class DataInitListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    UserRepository userRepository;
    @Autowired
    RoleRepository roleRepository;

    private boolean alreadySetup = false;

    public Boolean checkSetup() {
        if (alreadySetup) return true;

        userRepository.deleteAll();
        roleRepository.deleteAll();
        return false;
    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {

        if (checkSetup()) { return; }

        Role r1 = new Role("ROLE_ADMIN");
        Role r2 = new Role("ROLE_USER");
        User u1 = new User("myadmin", bCryptPasswordEncoder.encode("myadmin"));
        User u2 = new User("myuser", bCryptPasswordEncoder.encode("myuser"));

        u1.getRoles().add(r1);
        u2.getRoles().add(r2);
        userRepository.save(u1);
        userRepository.save(u2);

        alreadySetup = true;
    }
}

Secondly, we need to know how to configure Spring Security.

We would have a test resource controller

HomeController.java


WebSecurityConfig.java

@Configuration
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {


    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public MyUserDetailsService userDetailsService() {
        return new MyUserDetailsService();
    }




    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                    .antMatchers("/admin").hasRole("ADMIN")
                    .antMatchers("/user").hasAnyRole("ADMIN", "USER")
                    .antMatchers("/").permitAll()
                .and().formLogin();

    }

}

Leave a Reply