728x90
๋ฐ˜์‘ํ˜•

 

์‹œํ๋ฆฌํ‹ฐ ๋ฒ„์ „๋ณ„ ํŠน์„ฑ

 

: ์Šคํ”„๋ง์€ ๋ฒ„์ „์— ๋”ฐ๋ผ ๊ตฌํ˜„ ๋ฐฉ์‹์ด ๋ณ€๊ฒฝ๋˜๋Š”๋ฐ ์‹œํ๋ฆฌํ‹ฐ์˜ ๊ฒฝ์šฐ ํŠนํžˆ ์„ธ๋ถ€ ๋ฒ„์ „๋ณ„๋กœ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์ด ๋งŽ์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ฒ„์ „๋งˆ๋‹ค ๊ตฌํ˜„ ํŠน์ง•์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค

 

์ƒˆ๋กœ์šด ๋ฒ„์ „์ด ์ถœ์‹œ๋  ๋•Œ๋งˆ๋‹ค GitHub์˜ Spring ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ Security์˜ Release ํ•ญ๋ชฉ์„ ํ†ตํ•ด ๋ณ€๊ฒฝ๋œ ์ ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค

Releases · spring-projects/spring-security (github.com)

 

Releases · spring-projects/spring-security

Spring Security. Contribute to spring-projects/spring-security development by creating an account on GitHub.

github.com

 

 

 

์ฃผ์š” ๋ฒ„์ „๋ณ„ ๊ตฌํ˜„

 

- ์Šคํ”„๋ง ๋ถ€ํŠธ 2.X.X ~ 2.6.X (์Šคํ”„๋ง 5.X.X ~ 5.6.X)

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

				http
	        .authorizeRequests()
            .antMatchers("/").authenticated()
            .anyRequest().permitAll();

    }
}

 

- ์Šคํ”„๋ง ๋ถ€ํŠธ 2.7.X ~ 3,0.X (์Šคํ”„๋ง 5.7.X M2 ~ 6.0.X)

public class SpringSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
						.authorizeHttpRequests()
			            .requestMatchers("/admin").hasRole("ADMIN")
			            .anyRequest().authenticated();

        return http.build();
    }
}

 

- ์Šคํ”„๋ง ๋ถ€ํŠธ 3.1.X ~ (์Šคํ”„๋ง 6.1.X ~) 

public class SpringSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
            .authorizeHttpRequests((auth) -> auth
                  .requestMatchers("/login", "/join").permitAll()
                  .anyRequest().authenticated()
        );

        return http.build();
    }
}

 

** 3.1.X ๋ฒ„์ „๋ถ€ํ„ฐ ๋žŒ๋‹คํ˜•์‹ ํ‘œํ˜„ ํ•„์ˆ˜...

 

 

Config ์„ค์ • ํ›„ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€

 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ Config ํด๋ž˜์Šค ์„ค์ • ํ›„ ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†๋Š” ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ… ๋˜์ง€ ์•Š๊ณ  ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๊ฐ€ ๋ฐœ์ƒ....

 

์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Config ํด๋ž˜์Šค๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์„ค์ •๋„ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

 

 

์ปค์Šคํ…€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ :  mustache

 

- login.mustache

- ๋กœ๊ทธ์ธ : ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ POST ์š”์ฒญ ๊ฒฝ๋กœ

 

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    login page
    <hr>
    <form action="/loginProc" method="post" name="loginForm">
        <input id="username" type="text" name="username" placeholder="id"/>
        <input id="password" type="password" name="password" placeholder="password"/>
        <input type="submit" value="login"/>
    </form>
</body>
</html>

 

 

LoginController

package com.example.testsecurity.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {

    @GetMapping("/login")
    public String loginP() {

        return "login";
    }
}

 

 

Security Config ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์„ค์ • ๋ฐ ๋กœ๊ทธ์ธ ๊ฒฝ๋กœ

 

 

admin ํŽ˜์ด์ง€๋กœ ๊ฐ€๋„ ๋ฐ”๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ •..

package com.example.testsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{

        http
                .authorizeHttpRequests((auth) -> auth
                        .requestMatchers("/", "/login", "/loginProc").permitAll()
                        .requestMatchers("/admin").hasRole("ADMIN")
                        .requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
                        .anyRequest().authenticated()
                );

		
        // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์ ‘๊ทผ ์ถ”๊ฐ€ํ•˜๊ธฐ
        http
                .formLogin((auth) -> auth.loginPage("/login")
                        .loginProcessingUrl("/loginProc")
                        .permitAll()
                );
		
        // ํ† ํฐ์„ ๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉด ๋กœ๊ทธ์ธ์ด ์ง„ํ–‰์ด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ถ”ํ›„์— ํ‘ผ๋‹ค๊ณ  ํ•˜์‹ฌ...
        http
                .csrf((auth) -> auth.disable());


        return http.build();
    }
}

 

 

๊ทผ๋ฐ mustache ์™œ ์”€??

=> https://velog.io/@qowl880/SpringBoot-Mustache

 

[SpringBoot(2)] Mustache

์ด์ „๊นŒ์ง€ ์ง„ํ–‰ํ–ˆ๋˜ ์‹ค์Šต์€ ๊ธฐ๋Šฅ๋งŒ ๋„ฃ์–ด APIํ†ต์‹ ์„ swagger๋ฅผ ํ†ตํ•ด ์ง„ํ–‰ํ–ˆ๋‹ค๋ฉด ์ด์ œ๋Š” ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ €๊ฐ€ ๋ณผ์ˆ˜์žˆ๋Š” viewํ™”๋ฉด์œผ๋กœ ์ถœ๋ ฅ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ์ง„ํ–‰ํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค

velog.io

 

 

์‹œํ๋ฆฌํ‹ฐ ์•”ํ˜ธํ™”

 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ(๋กœ๊ทธ์ธ) ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ์— ๋Œ€ํ•ด ๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ์•”ํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜์—ฌ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ๋Œ€์กฐ๋œ๋‹ค. 

๋”ฐ๋ผ์„œ ํšŒ์›๊ฐ€์ž…์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด์„œ ์•”ํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค

 

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋Š” ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด BCrypt Password Encorder๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๊ถŒ์žฅํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ return ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด @Bean ์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค

 

 

๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ ์•”ํ˜ธํ™”

 

- ์–‘๋ฐฉํ–ฅ(๋Œ€์นญํ‚ค, ๋น„๋Œ€์นญํ‚ค)

- ๋‹จ๋ฐฉํ–ฅ(ํ—ค์‹œ)

 

 

Security Config ์•”ํ˜ธํ™” Bean ์ถ”๊ฐ€

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {

    return new BCryptPasswordEncoder();
}

 

 

 

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ข…๋ฅ˜์™€ ORM

 

ํšŒ์› ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” MYSQL ์—”์ง„์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ ‘๊ทผ์€ Spring Date JPA ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค

 

 

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์˜์กด์„ฑ

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.mysql:mysql-connector-j'
}

 

 

๋ณ€์ˆ˜ ์„ค์ •

  • application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://์•„์ดํ”ผ:3306/๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true
spring.datasource.username=์•„์ด๋””
spring.datasource.password=๋น„๋ฐ€๋ฒˆํ˜ธ

 

 

ํšŒ์›๊ฐ€์ž… ๋กœ์ง

 

ํšŒ์›์ •๋ณด๋ฅผ ํ†ตํ•ด ์ธ์ฆ ์ธ๊ฐ€ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ํšŒ์› ๊ฐ€์ž…์„ ์ง„ํ–‰ํ•œ ๋’ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํšŒ์› ์ •๋ณด๋ฅผ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค

 

 

ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ : mustache

 

- join.mustache

<form action="/joinProc" method="post" name="joinForm">
    <input type="text" name="username" placeholder="Username"/>
    <input type="password" name="password" placeholder="Password"/>
		<input type="submit" value="Join"/>
</form>

 

- JoinDTO

package com.example.testsecurity.dto;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class JoinDTO {

    private String username;
    private String password;
}

 

- JoinController

package com.example.testsecurity.controller;

import com.example.testsecurity.dto.JoinDTO;
import com.example.testsecurity.service.JoinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class JoinController {

    @Autowired
    private JoinService joinService;


    @GetMapping("/join")
    public String joinP() {

        return "join";
    }


    @PostMapping("/joinProc")
    public String joinProcess(JoinDTO joinDTO) {

        System.out.println(joinDTO.getUsername());

        joinService.joinProcess(joinDTO);


        return "redirect:/login";
    }
}

 

- JoinService

package com.example.testsecurity.service;

import com.example.testsecurity.dto.JoinDTO;
import com.example.testsecurity.entity.UserEntity;
import com.example.testsecurity.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class JoinService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    public void joinProcess(JoinDTO joinDTO) {


        //db์— ์ด๋ฏธ ๋™์ผํ•œ username์„ ๊ฐ€์ง„ ํšŒ์›์ด ์กด์žฌํ•˜๋Š”์ง€?


        UserEntity data = new UserEntity();

        data.setUsername(joinDTO.getUsername());
        data.setPassword(bCryptPasswordEncoder.encode(joinDTO.getPassword()));
        data.setRole("ROLE_USER");


        userRepository.save(data);
    }
}

 

 

 

-UserEntity

package com.example.testsecurity.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Setter
@Getter
public class UserEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String username;
    private String password;

    private String role;
}

 

 

Table ์ƒ์„ฑ : Hibernate ddl ์„ค์ •

 

- application properties

spring.jpa.hibernate.ddl-auto=none		// none์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ํ…Œ์ด๋ธ”์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์ง€๋กฑ
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

- UserRepository

package com.example.testsecurity.repository;

import com.example.testsecurity.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<UserEntity, Integer> {

}

 

- SecurityConfig ์ ‘๊ทผ ๊ถŒํ•œ

http
          .authorizeHttpRequests((auth) -> auth
                  .requestMatchers("/", "/login", "/loginProc", "/join", "/joinProc").permitAll()
                  .requestMatchers("/admin").hasRole("ADMIN")
                  .requestMatchers("/my/**").hasAnyRole("ADMIN", "USER")
                  .anyRequest().authenticated()
          );

 

728x90
๋ฐ˜์‘ํ˜•

+ Recent posts