spring board ํ”„๋กœ์ ํŠธ security ์ ์šฉ

2023. 7. 7. 15:35ใ†Spring

**์‹œํ๋ฆฌํ‹ฐ๋ž‘ css ๋‚˜ js ๋“ฑ ๊ฐ™์ด ์žˆ์œผ๋ฉด ์ถฉ๋Œ๋‚จ

Securityconfig์— ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ ์ž‘์„ฑํ•ด์•ผ ํ•จ.

//css, js, img ๋“ฑ ์ถฉ๋Œ ์•ˆ ๋‚˜๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return (web) -> web.ignoring().requestMatchers("/js/**", "/css/**", "/img/**");
}

 

 ํšŒ์›๊ฐ€์ž… ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ์„ค์ •.

> ์•”ํ˜ธํ™” ์„ค์ •ํ•˜๋ ค๋ฉด ์•”ํ˜ธํ™” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•จ.

SecurityConfig์— @Bean์œผ๋กœ ๊ฐ์ฒด ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋จ.(์œ„์น˜ ์ƒ๊ด€ ์—†์Œ)

//์•”ํ˜ธํ™” ๊ฐ์ฒด ์ƒ์„ฑ
@Bean
public PasswordEncoder getPasswordEncoder() {

    return new BCryptPasswordEncoder();
}

ํšŒ์›๊ฐ€์ž… controller๊ฐ€ ์žˆ๋Š” MemberController์— ์•”ํ˜ธํ™” ๊ฐ์ฒด ๋ถˆ๋Ÿฌ์˜ด

//์•”ํ˜ธํ™” ๊ฐ์ฒด
@Autowired
private PasswordEncoder encoder;

ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ์— ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ์ž‘์—… ์ฝ”๋“œ ์ž‘์„ฑ.

//ํšŒ์›๊ฐ€์ž…
@PostMapping("/join")
public String join(MemberVO memberVO) {
    //๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ์ž‘์—…
    String encodePw = encoder.encode(memberVO.getMemPw());
    memberVO.setMemPw(encodePw);

    memberService.joinMember(memberVO);

    return "redirect:/member/login";

}

 

 

์‹œํ๋ฆฌํ‹ฐ๋กœ ๋กœ๊ทธ์ธ ๋ฐฉ์‹ ๋ณ€๊ฒฝ

> ๋กœ๊ทธ์ธ ์ž๋™์œผ๋กœ ์‹คํ–‰์‹œ์ผœ์ฃผ๋Š” userDetailsServiceImpl ์ƒ์„ฑํ•ด์•ผ ํ•จ.

์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ๋กœ๊ทธ์ธ ํ•  ์ˆ˜ ์žˆ๊ฒŒ UserDetails์— ๋กœ๊ทธ์ธ ์ •๋ณด ์„ธํŒ…

 

๋กœ๊ทธ์ธ ํ•  ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ์„ ์œ„ํ•ด mapper ์ˆ˜์ •

์ด์ „์˜ ๋กœ๊ทธ์ธํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋จ.

<!-- ๋กœ๊ทธ์ธ ์ •๋ณด ์กฐํšŒ ์ฟผ๋ฆฌ -->
<select id="login" resultMap="member">
    SELECT MEM_ID
        , MEM_NAME
        , IS_ADMIN
        , MEM_PW
    FROM SPRING_BOARD_MEMBER
    WHERE MEM_ID = #{memId}

</select>

์ฑ„์›Œ์ค„ ๋นˆ ๊ฐ’์ด ํ•˜๋‚˜๋กœ ์ค„์—ˆ์Œ

> Id๊ฐ’๋งŒ ๋ฐ›์•„์˜ค๊ฒŒ MemberService ๋ฉ”์†Œ๋“œ ์ˆ˜์ •

//์‹œํ๋ฆฌํ‹ฐ ๋กœ๊ทธ์ธ
MemberVO login(String memId);

MemberServiceImpl๋„ ๋™์ผํ•˜๊ฒŒ ์ˆ˜์ •.

//์‹œํ๋ฆฌํ‹ฐ ๋กœ๊ทธ์ธ
@Override
public MemberVO login(String memId) {
    return sqlSession.selectOne("memberMapper.login", memId);	
}

 

UserDetailsServiceImpl๋กœ ๋Œ์•„์™€์„œ ๋กœ๊ทธ์ธ ์ •๋ณด ๋‹ด๊ธฐ.

๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ์„ ์œ„ํ•ด memberService ๊ฐ์ฒด ๋“ค๊ณ ์™€์•ผ ํ•จ.

@Resource ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ์ฒด ๊ฐ€์ ธ์˜ค๊ธฐ.

@Service("userDetailsService")//๊ฐ์ฒด ์ƒ์„ฑ
public class UserDetailsServiceImpl implements UserDetailsService {
	
	@Resource(name = "memberService")
	private MemberService memberService;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		
		//๋กœ๊ทธ์ธ ์ •๋ณด ์กฐํšŒ                     //๋กœ๊ทธ์ธํ•  ๋•Œ ์ž…๋ ฅํ•œ id๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„์˜ด
		MemberVO userInfo = memberService.login(username);
		
		//๋กœ๊ทธ์ธ ์‹œ ์ž…๋ ฅํ•œ ID๊ฐ€ ์—†๋Š” ๊ณ„์ •์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ ๊ฐ•์ œ ๋ฐœ์ƒ
		if(userInfo == null) {
			throw new UsernameNotFoundException("์˜ค๋ฅ˜");
		}
		
		//๋กœ๊ทธ์ธ ์ •๋ณด ๋‹ด๊ธฐ
		UserDetails user = User.withUsername(userInfo.getMemId())
								.password(userInfo.getMemPw())
								.roles(userInfo.getIsAdmin()) //๊ถŒํ•œ์ด 'Y' / 'N' ์œผ๋กœ ๋“ค์–ด์˜ด
								.build();
		
		return user;
	}

}

 

SecurityConfig์— ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ ‘๊ทผ ํ—ˆ์šฉํ•˜๊ฒŒ ์„ค์ •.

@Configuration
@EnableWebSecurity
public class SecurityConfig {
	
	@Bean
	public SecurityFilterChain filterChain (HttpSecurity security) throws Exception {
		
		//์ธ์ฆ ์ธ๊ฐ€ ์„ค์ •
		security.csrf().disable()
				.authorizeHttpRequests()
					.requestMatchers("/board/list"
							, "/member/join"
                            , "/member/login").permitAll()
					//.requestMatchers(HttpMethod.POST ,"/join").permitAll() POST ๋ฐฉ์‹ ์ด๋™๊ฒฝ๋กœ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
					.anyRequest().authenticated()
				.and()
					.formLogin()
					.loginPage("/member/login")
					.usernameParameter("memId")
					.passwordParameter("memPw")
					.loginProcessingUrl("/loginProcess") //๋กœ๊ทธ์ธ ์‹œ๋„ํ•˜๋Š” ๊ฒฝ๋กœ๋ž‘, ๋กœ๊ทธ์ธ ํ•˜๋Š” ํŽ˜์ด์ง€ ๊ฒฝ๋กœ ๊ฐ™์•„๋„ ๋จ.
					.defaultSuccessUrl("/member/loginResult", true) //๋ฌด์กฐ๊ฑด ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ true ๋„ฃ์–ด์คŒ
					//.failureUrl("/member/loginResult")
					.failureHandler(getFailureHandler()) //์‹คํŒจํ–ˆ์„ ๋•Œ ํด๋ž˜์Šค ์‹คํ–‰ ๋จ (์‹คํŒจํ–ˆ์„ ๋•Œ ํด๋ž˜์Šค์—์„œ ์—ฌ๋Ÿฌ ์กฐ์ž‘ ๊ฐ€๋Šฅ)
					.permitAll();
		
		return security.build();
	}
	
	//์•”ํ˜ธํ™” ๊ฐ์ฒด ์ƒ์„ฑ
	@Bean
	public PasswordEncoder getPasswordEncoder() {
		
		return new BCryptPasswordEncoder();
	}
	
	//css, js, img ๋“ฑ ์ถฉ๋Œ ์•ˆ ๋‚˜๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
	@Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/js/**", "/css/**", "/img/**");
    }
}

๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ์ง€์ •ํ•œ ํด๋ž˜์Šค๋กœ ์ด๋™

FailureHandler ํด๋ž˜์Šค ์ƒ์„ฑ

์ด ํด๋ž˜์Šค๋Š” SimpleUrlAuthenticationFailureHandler ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์•ผ ํ•จ

SimpleUrlAuthenticationFailureHandler ํด๋ž˜์Šค๋Š” ์‹คํŒจ ์‹œ ์‹คํ–‰๋˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ด๋ฏธ ๊ฐ€์ง€๊ณ  ์žˆ์Œ.

ํ•ด๋‹น ๋ฉ”์†Œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์„œ ์‚ฌ์šฉ.

 

@Override					//์š”์ฒญ : ๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ ๊ฐ€๋Šฅ	//์‘๋‹ต
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException {
                                //์˜ˆ์™ธ ์ •๋ณด(๋กœ๊ทธ์ธ ์‹คํŒจ ์™œ ํ–ˆ๋Š”์ง€)
    super.onAuthenticationFailure(request, response, exception);
}

FailureHandler ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์ค˜์•ผ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Œ.

Securityconfig๋กœ ๋Œ์•„๊ฐ€์„œ ์‹คํŒจ ์‹œ ์ž‘๋™ํ•  FailureHandler ๊ฐ์ฒด ์ƒ์„ฑ.

@Bean
//๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ์‹คํ–‰๋˜๋Š” ํด๋ž˜์Šค ๊ฐ์ฒด ์ƒ์„ฑ
public FailureHandler getFailureHandler() {

    return new FailureHandler();
}

์ธ์ฆ ์ธ๊ฐ€ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ์—์„œ ์‹คํŒจ ์‹œ FailureHandler ํด๋ž˜์Šค ์‹คํ–‰ ๋˜๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ getFailureHandler ๋ฉ”์†Œ๋“œ ๋„ฃ์–ด์คŒ.

์ด์ œ ๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ์ž‘๋™ํ•  ์ฝ”๋“œ๋ฅผ FailureHandler์— ์ž‘์„ฑ.

//๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋Š” ํด๋ž˜์Šค
public class FailureHandler extends SimpleUrlAuthenticationFailureHandler{

	@Override							//์š”์ฒญ : ๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ ๊ฐ€๋Šฅ				//์‘๋‹ต
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
									//์˜ˆ์™ธ ์ •๋ณด(๋กœ๊ทธ์ธ ์‹คํŒจ ์™œ ํ–ˆ๋Š”์ง€)
		
		//์—๋Ÿฌ ๋ฉ”์„ธ์ง€
		String eMsg = "";
		
		//์–ด๋–ค ์˜ˆ์™ธ๋ƒ์— ๋”ฐ๋ผ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฆ„
		if(exception instanceof BadCredentialsException) {
								//์ž…๋ ฅํ•œ ์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ž˜๋ชป๋จ.
			eMsg = "์•„์ด๋”” ํ˜น์€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.";
			
		}
		else if (exception instanceof UsernameNotFoundException ){
									//์ž…๋ ฅํ•œ ๊ณ„์ •์ด ์—†์„ ๋•Œ
			eMsg = "ํ•ด๋‹น ๊ณ„์ •์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.";
		}
		else {
			eMsg = "์•Œ ์ˆ˜ ์—†๋Š” ์ด์œ ๋กœ ๋กœ๊ทธ์ธ์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž์—๊ฒŒ ๋ฌธ์˜ํ•˜์‹ญ์‹œ์˜ค.";
		}
		
		//๋กœ๊ทธ์ธ ์‹œ ์ž…๋ ฅํ•œ id๊ฐ’ (๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ๋กœ๊ทธ์ธ์ฐฝ์— ๋‹ค์‹œ ๋„์šฐ๊ธฐ ์œ„ํ•จ)
		String memId = request.getParameter("memId");
		
		//๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ํŽ˜์ด์ง€ ์ด๋™
		//์›น ์ƒ์—์„œ ์ ์šฉ๋˜๋Š” utf-8๋กœ ๋ฌธ์ž์—ด ์ธ์ฝ”๋”ฉ ํ•ด์•ผ ํ•จ. (์ธ์ฝ”๋”ฉ ์•ˆ ํ•˜๋ฉด ์œ„ํ—˜ํ•œ ๋ฐ์ดํ„ฐ๋กœ ์ธ์‹ํ•˜์—ฌ ์•ˆ ๋„˜์–ด๊ฐ)
		eMsg = URLEncoder.encode(eMsg, "UTF-8");
		setDefaultFailureUrl("/member/login?eMsg=" + eMsg + "&isError=true&memId=" + memId);
		
		System.out.println(eMsg);
		
		super.onAuthenticationFailure(request, response, exception);
	}
	
}

 

๋กœ๊ทธ์ธ ์‹คํŒจํ•˜๋ฉด ๋‹ค์‹œ ๋กœ๊ทธ์ธ ์ฐฝ์œผ๋กœ ๊ฐ€๊ฒŒ ๋จ.

ํŽ˜์ด์ง€ ์ด๋™ํ•  ๋•Œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ isError(์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•ˆ ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€) ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ๊ฐ€๊ฒŒ ํ•จ.

๊ทธ๋ฆฌ๊ณ  ์ด์ „์— ์ž…๋ ฅํ•œ id๋„ ๋œฐ ์ˆ˜ ์žˆ๊ฒŒ id๊ฐ’๋„ ๊ฐ€์ ธ๊ฐ„๋‹ค.

 

MemberController ์ž‘์„ฑ

๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ด๋™ controller์—์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€, ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์—ฌ๋ถ€ ๋ฐ์ดํ„ฐ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ.

์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์—ฌ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„์ฃผ๊ณ  ๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ ํ•„์ˆ˜๊ฐ’(์‹คํŒจ ์‹œ๋งŒ ๋„˜์–ด์˜ด)์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— @RequestParam ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ.

๋ฐ์ดํ„ฐ login.html๋กœ ๋„˜๊ธฐ๊ธฐ.

๋„˜์–ด์˜จ id ๊ฐ’์€ ์ปค๋งจ๋“œ ๊ฐ์ฒด memberVO์—์„œ ๋ฐ›์•„์„œ html๋กœ ์ž๋™ ์ „๋‹ฌ๋จ!

//๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ด๋™
@GetMapping("/login")
public String loginForm(MemberVO memberVO
        //๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ ํ•„์ˆ˜ X(๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ๋งŒ ๋„˜์–ด์˜ด)
        , @RequestParam(required = false) String eMsg
        , @RequestParam(required = false, defaultValue = "false") String isError
        , Model model) { 

    model.addAttribute("eMsg", eMsg);
    model.addAttribute("isError", isError);


    return "content/member/login"; 
}

login.html์—์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ์ดํ„ฐ์™€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์—ฌ๋ถ€ ๋ฟŒ๋ ค์คŒ.

th:field๋กœ memId ์„ค์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „์— ์ž…๋ ฅํ•œ id๋ฅผ value ๊ฐ’์œผ๋กœ ์ž๋™์œผ๋กœ ๊ฐ€์ ธ์˜ด

<div>์•„์ด๋”” <input type="text" th:field="*{memId}"></div>
<!-- ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ -->
<div th:if="${isError}" th:text="${eMsg}"></div>
<div>๋น„๋ฐ€๋ฒˆํ˜ธ <input type="password" th:field="*{memPw}"></div>
<div>
    <input type="submit" value="๋กœ๊ทธ์ธ">
    <input type="button" value="ํšŒ์›๊ฐ€์ž…" th:onclick="|location.href='@{/member/join}';|">
</div>

 

๋กœ๊ทธ์ธ ์‹คํŒจํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๊ณ  ์ด์ „์— ์ž…๋ ฅํ•œ id๊ฐ’ ๋‚˜์˜ด

์ด์ œ ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ๋กœ๊ทธ์ธ ์ž๋™์œผ๋กœ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— MemberController์˜ ๋กœ๊ทธ์ธ controller ์‚ญ์ œ

 

 

๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ์ƒ๋‹จ์— ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ์˜ ์ด๋ฆ„ ๋œจ๊ฒŒ ์„ค์ •.

๋กœ๊ทธ์ธ ์„ฑ๊ณตํ•˜๋ฉด  /member/loginResult๋กœ ํŽ˜์ด์ง€ ์ด๋™

MemberController์— ํŽ˜์ด์ง€ ์ด๋™ ๋ฉ”์†Œ๋“œ ์ž‘์„ฑ

//๋กœ๊ทธ์ธ ํ›„ ์ด๋™ํ•˜๋Š” ํŽ˜์ด์ง€
@GetMapping("loginResult")
public String loginResult () {

    return "content/member/login_result";
}

login_result.html ์ˆ˜์ •

์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ• ์“ฐ๋ ค๋ฉด html์— ์ƒ๋‹จ์— ์•„๋ž˜ ์ฝ”๋“œ ์ถ”๊ฐ€

xmlns:sec="http://www.thymeleaf.org/extras/spring-security"

์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ• ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ alert ์ฐฝ ๋œจ๊ฒŒ ์ฝ”๋“œ ๋ณ€๊ฒฝ. 

<!-- ๋กœ๊ทธ์ธ ์„ฑ๊ณต -->
<div sec:authorize="isAuthenticated()">
	<script type="text/javascript">
		alert('๋กœ๊ทธ์ธ ์„ฑ๊ณต');
		location.href='/board/list';
	</script>
</div>

๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ์— ์ž‘๋™๋˜๋Š” ์ด์ „์— ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” ์ง€์›Œ๋„ ๋จ!

 

๋‹ค์‹œ MemberController๋กœ ๋Œ์•„์™€์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ด๋ฆ„ ๋ฝ‘๋Š” ์ฝ”๋“œ ์ž‘์„ฑ.

๋กœ๊ทธ์ธ ํ›„ ์ด๋™ํ•˜๋Š” ํŽ˜์ด์ง€ controller์—์„œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ฐพ์•„์„œ ์„ธ์…˜์— ๋“ฑ๋กํ•ด์•ผํ•จ.

์‹œํ๋ฆฌํ‹ฐ๋Š” ์„ธ์…˜์— ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ์ด ์•„์ด๋”” ๊ฐ’๊ณผ ๊ถŒํ•œ๋งŒ ๋“ค๊ณ  ์žˆ์–ด์„œ ๋ฐ”๋กœ ์ด๋ฆ„ ๋ฝ‘์„ ์ˆ˜ ์—†์Œ.

์šฐ์„ , ๋งค๊ฐœ๋ณ€์ˆ˜์— Authentication ์ถ”๊ฐ€ ์„ธ์…˜์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๋ฝ‘๊ธฐ

//๋กœ๊ทธ์ธ ํ›„ ์ด๋™ํ•˜๋Š” ํŽ˜์ด์ง€
@GetMapping("loginResult")
public String loginResult (Authentication authentication, HttpSession session) {

    //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ๋กœ๊ทธ์ธํ•œ ํšŒ์›์˜ ์ด๋ฆ„์„ ์ฐพ์•„์„œ ์„ธ์…˜์— ๋“ฑ๋ก
    User user = (User)authentication.getPrincipal();

    return "content/member/login_result";
}

ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์•„์ด๋”” ๊ฐ™์€ ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์กฐํšŒํ•ด์•ผ ๋จ.

member-mapper์—์„œ ์ด๋ฆ„ ์กฐํšŒ ์ฟผ๋ฆฌ ์ž‘์„ฑ

<!-- ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ ์•„์ด๋”” ์กฐํšŒ -->
<select id="getUserNameById" resultType="String">
    SELECT MEM_NAME
    FROM SPRING_BOARD_MEMBER
    WHERE MEM_ID = #{memId}
</select>

MemberService ๋ฉ”์†Œ๋“œ ์ž‘์„ฑ

//๋กœ๊ทธ์ธํ•œ ํšŒ์› ์ด๋ฆ„ ์ •๋ณด
String getUserNameById(String memId);

MemberServiceImpl ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„

//๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ ์ด๋ฆ„ ์กฐํšŒ
@Override
public String getUserNameById(String memId) {

    return sqlSession.selectOne("memberMapper.getUserNameById", memId);
}

MemberController ์ž‘์„ฑ ๋ฉ”์†Œ๋“œ ์‹คํ–‰

์กฐํšŒํ•œ ํšŒ์› ์ด๋ฆ„์„ ์„ธ์…˜์— ๋ฐ์ดํ„ฐ ์„ธํŒ…

//๋กœ๊ทธ์ธ ํ›„ ์ด๋™ํ•˜๋Š” ํŽ˜์ด์ง€
@GetMapping("loginResult")
public String loginResult (Authentication authentication, HttpSession session) {

    //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ๋กœ๊ทธ์ธํ•œ ํšŒ์›์˜ ์ด๋ฆ„์„ ์ฐพ์•„์„œ ์„ธ์…˜์— ๋“ฑ๋ก
    User user = (User)authentication.getPrincipal();
    String userName = memberService.getUserNameById(user.getUsername());
    
    //์„ธ์…˜์— ํšŒ์› ์ด๋ฆ„ ์„ธํŒ…
    session.setAttribute("userName", userName);
    
    return "content/member/login_result";
}

 header.html๋กœ ๊ฐ€์„œ ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ ์ด๋ฆ„ ๋ฟŒ๋ ค์ฃผ๋ฉด ๋จ.

<div sec:authorize="isAuthenticated()">
    [[${session.userName}]]๋‹˜ ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค.
    <a th:href="@{/member/logout}">LOGOUT</a> 
</div>

๋กœ๊ทธ์ธ ์„ฑ๊ณตํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์ƒ๋‹จ์— ์ด๋ฆ„ ์ž˜ ๊ฐ€์ ธ์˜ด.

 

์‹œํ๋ฆฌํ‹ฐ ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ์„ค์ •.

์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ์ž๋™์œผ๋กœ ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— MemberContoller์˜ ์ด์ „์— ์ž‘์„ฑํ•œ ๋กœ๊ทธ์•„์›ƒ ์ปจํŠธ๋กค๋Ÿฌ ์‚ญ์ œ

SecurityConfig ์ž‘์„ฑ

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

    //์ธ์ฆ ์ธ๊ฐ€ ์„ค์ •
    security.csrf().disable()
            .authorizeHttpRequests()
                .requestMatchers("/board/list"
                                , "/member/join"
                                , "/member/login").permitAll()
                //.requestMatchers(HttpMethod.POST ,"/join").permitAll() POST ๋ฐฉ์‹ ์ด๋™๊ฒฝ๋กœ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
                .anyRequest().authenticated()
            .and()
                .formLogin()
                .loginPage("/member/login")
                .usernameParameter("memId")
                .passwordParameter("memPw")
                .loginProcessingUrl("/loginProcess") //๋กœ๊ทธ์ธ ์‹œ๋„ํ•˜๋Š” ๊ฒฝ๋กœ๋ž‘, ๋กœ๊ทธ์ธ ํ•˜๋Š” ํŽ˜์ด์ง€ ๊ฒฝ๋กœ ๊ฐ™์•„๋„ ๋จ.
                .defaultSuccessUrl("/member/loginResult", true) //๋ฌด์กฐ๊ฑด ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ true ๋„ฃ์–ด์คŒ
                //.failureUrl("/member/loginResult")
                .failureHandler(getFailureHandler()) //์‹คํŒจํ–ˆ์„ ๋•Œ ํด๋ž˜์Šค ์‹คํ–‰ ๋จ (์‹คํŒจํ–ˆ์„ ๋•Œ ํด๋ž˜์Šค์—์„œ ์—ฌ๋Ÿฌ ์กฐ์ž‘ ๊ฐ€๋Šฅ)
                .permitAll() 
            .and()
                .logout()
                .logoutUrl("/member/logout")
                .invalidateHttpSession(true) //๋กœ๊ทธ์•„์›ƒ ํ•˜๋ฉด ์„ธ์…˜ ๋ฐ์ดํ„ฐ ์ง€์šฐ๋Š” ๊ฒƒ
                .logoutSuccessUrl("/board/list");

    return security.build();
}

logoutUrl์™€ header.html์˜ ๋กœ๊ทธ์•„์›ƒ ๊ฒฝ๋กœ ๋งž์ถฐ์ฃผ๋ฉด ๋จ!

๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์€ ๋กœ๊ทธ์ธ ํ–ˆ์„ ๋•Œ๋งŒ ๋ณด์—ฌ์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ•์œผ๋กœ ์„ค์ •.

 

 

์ถ”๊ฐ€์ ์ธ ๋ฒ„ํŠผ ์ปจํŠธ๋กค

1. header.html์˜ ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์› ๊ฐ€์ž… ๋ฒ„ํŠผ์€ ๋กœ๊ทธ์ธ ์•ˆ ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ณด์—ฌ์•ผ ๋จ.

์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ• ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ์•ˆ ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ณด์ด๊ฒŒ ์ฝ”๋“œ ์ž‘์„ฑ.

2.board_list.html์˜ ๊ธ€๋“ฑ๋ก ๋ฒ„ํŠผ ๋กœ๊ทธ์ธ ํ•œ ๊ฒฝ์šฐ๋งŒ ๋ณด์ด๊ฒŒ ์„ค์ •.

html ์ƒ๋‹จ์— ์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ• ์ฝ”๋“œ ์ถ”๊ฐ€

xmlns:sec="http://www.thymeleaf.org/extras/spring-security"

 

์•„๋ž˜์ฒ˜๋Ÿผ ๋กœ๊ทธ์ธํ•œ ๊ฒฝ์šฐ๋งŒ ๋ณด์ด๊ฒŒ ์ฝ”๋“œ ์ถ”๊ฐ€.

 

 

 

๊ธ€ ์ƒ์„ธ ํŽ˜์ด์ง€

1. ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€์— ํ•˜๋‹จ์— ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •, ์‚ญ์ œ ๋ฒ„ํŠผ ์ปจํŠธ๋กค

๋กœ๊ทธ์ธ ๋˜์—ˆ์„ ๋•Œ๋งŒ ๋ฒ„ํŠผ ๋ณด์ด๊ฒŒ ์‹œํ๋ฆฌํ‹ฐ ๋ฌธ๋ฒ•์œผ๋กœ ์„ค์ •

๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ์ด ๊ธ€ ์ž‘์„ฑํ•œ ์‚ฌ๋žŒ๊ณผ ์ผ์น˜ or ๊ด€๋ฆฌ์ž์ธ ๊ฒฝ์šฐ(ROLE์ด 'Y')

์ˆ˜์ •, ์‚ญ์ œ ๋ฒ„ํŠผ ๋ณด์—ฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— if๋ฌธ์œผ๋กœ ์กฐ๊ฑด ์„ค์ •

<div th:if="${board.boardWriter == #authentication.name}">
    <input type="button" value="์‚ญ์ œ" th:onclick="goDelete([[${board.boardNum}]]);">
    <input type="button" value="์ˆ˜์ •" th:onclick="goUpdate([[${board.boardNum}]]);">
</div>
    <!-- ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ == ๊ด€๋ฆฌ์ž -->
<div sec:authorize="hasRole('ROLE_Y')">
    <div th:if="${board.boardWriter !== #authentication.name}">
        <input type="button" value="์‚ญ์ œ" th:onclick="goDelete([[${board.boardNum}]]);">
        <input type="button" value="์ˆ˜์ •" th:onclick="goUpdate([[${board.boardNum}]]);">
    </div>
</div>

 

2. ๋Œ“๊ธ€ ๋“ฑ๋ก ๋ฒ„ํŠผ ๋กœ๊ทธ์ธ ํ–ˆ์„ ๋•Œ๋งŒ ๋ณด์ด๊ฒŒ

์Šคํ”„๋ง ๋ณด๋“œ ๊ถŒํ•œ n - ์ผ๋ฐ˜์‚ฌ์šฉ์ž y - ๊ด€๋ฆฌ์ž