콘텐츠로 바로가기
프링향의 기록

프링향의 기록

웹프로그래머의 일상/취미

  • 홈
  • IT
    • JAVA
    • PHP
    • 데이터베이스
      • MYSQL
      • MSSQL
    • JAVASCRIPT
    • jQuery
    • 기타
  • 취미
    • 게임
    • 스노우보드
    • NAS
  • 일상
    • 나의 일상
    • 아이들 일상
  • 잡동사니
  • 오버워치

태그: Spring Security 설정

작성일자 2020년 5월 20일2020년 5월 20일

Spring Boot Security(Spring Security) 로그인/로그아웃 설정

여기저기 찾아보고, 공식홈페이지도 찾아보고…

Spring Boot Security 로 검색하면..

스프링부트에서의 Spring Security 설정법이 많이 나오지 않는다..

Spring Framework 에서 설정했던 spring-security.xml 과
같은 xml을 기반으로 한 설정 방법이 우루루…

저 방법은… 이전에 정리해둔게 있으므로 패스..

+나는 스프링부트를 기준으로 하고 싶다!!
(제대로 된 건지는 모르겠으나.. 정상 작동은 되는중이라 포스팅 시작)

 

첫번째로 Spring Security 를 사용하기 위한 의존성 추가(pom.xml)

프로젝트 우클릭 -> Spring -> Edit Starters 클릭

 

Security 검색 -> Spring Security 선택 후 OK
(어라.. Spring Data JPA 는 사용 안하므로 제거해야지..)

Lombok 의 경우 Model 또는 DTO 또는 VO 생성 시

Getter, Setter 를 만들어 주지 않아도

@Data, @Getter, @Setter 와 같은 방식으로 어노테이션 한줄로 처리해주는
고마운 라이브러리..
(설치방법은 위 처럼 추가 후 해당 jar를 실행 후 IDE 를 선택해주는 것으로 끝난다.)
(ini 파일에 -javaagent:C:\sts-4.6.1.RELEASE\lombok.jar 가 추가됨)

데이터를 조회한 후 저장할 Model 생성

Member.java

@Data
public class Member {
	private String userId;
	private String userName;
	private String password;
}

 

MemberMapper.java

@Mapper
public interface MemberMapper {
	Member findByUserId(String userId);
}

이전에는 @Repository 를 사용하였는데.. @Mapper 어노테이션이 있기에 사용

 

MemberMapper.xml

<?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.ep.mapper.MemberMapper">
	<select id="findByUserId" parameterType="java.lang.String" resultType="com.medica.ep.model.Member">
		SELECT
			USER_ID AS userId,
			USER_NAME AS userName,
			PASSWORD AS password
		FROM USER
		WHERE USER_ID = #{userId}
	</select>
</mapper>

 

★ 여기서 부터 중요.. 삽질 많이 한 부분..

MemberService.java
(UserDetailsService 인터페이스를 implements 받아 구현한다)
(입력받은 아이디에 대한 정보를 조회하여 값을 return 해주는 클래스)
(권한 설정도 여기서 해줘야 할 것으로 보여짐)

@Service
public class MemberService implements UserDetailsService {
	
	@Autowired
	private MemberMapper memberMapper;
	
	@Override
	public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
		Member member = memberMapper.findByUserId(userId);
		List<GrantedAuthority> authorities = new ArrayList<>();
		
		if(member != null) {
			authorities.add(new SimpleGrantedAuthority("USER"));
		}else {
			new UsernameNotFoundException("아이디 없음");
		}
		//부서에 따라 권한 관리
		String role = "";
		String deptCd = member.getDeptCd();
		if("1000".equals(deptCd)){
			role = "DEPT";
		}
		authorities.add(new SimpleGrantedAuthority(role));
		//권한 설정 끝

		return new User(member.getUserId(), member.getPassword(), authorities);
	}
}

memberMapper.findByuserId(userId)

에서 조회된 결과를 기준으로 각 권한(ROLE)을 설정 해준다.

return 하는 부분에서 한참을 해매였는데…

https://spring.io/guides/gs/securing-web/

공홈에 있는 예제대로 만들어 본 다음 하나씩 바꾸어보니 되더라-_-

공홈에서는 User를 return 하는것이 아닐 ㅏUserDetails 라는 객체 자체를 return

하는 방식이나 권한이 여러개(ex : 관리자의 경우 관리자이면서 사용자) 인 경우

※ User 생성자에 있는 ID 와 Password는

memberService 를 호출하는 곳에서 로그인 시 입력한 ID 와 Password를 비교
(Spring Security 내부적으로 비교하는 것으로 보인다.. equals 니 이런게 안보임;;)

 

★Spring Boot Security 와 Spring Security 의 차별(?)성이 나타나는 부분..

WebSecurityConfig.java (클래스명은 자유)

Spring Security 에서는 Auth블라블라 Provider 블라블라~ 에서 권한을~~

였던 것 같은데… Spring Boot Security 의 경우 생각보다? 간단하다.
(그런거치고는 삽질을 많이 했지만…)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private MemberService memberService;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		//.antMatchers("/admin").hasRole("ADMIN")
		.antMatchers("/").permitAll()
		.anyRequest().authenticated()
		.and().csrf()
			.ignoringAntMatchers("/user/login", "/user/logout")
		.and().formLogin()
			.loginPage("/user/login").permitAll()
		.and().logout()
			.logoutUrl("/user/logout")
			.logoutSuccessUrl("/")
			.invalidateHttpSession(true)
			.permitAll();
	}

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

@SuppressWarnings("deprecation")
@Bean
public PasswordEncoder passwordEncoder() {
	return NoOpPasswordEncoder.getInstance();
	//return new BCryptPasswordEncoder();
	//return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

.antMatchers(“/admin”).hasRole(“ADMIN”) : /admin  경우 role 이 ADMIN
.antMatchers(“/”).permitAll() : “/” 경로는 모두 접근 가능
.anyRequest().authenticated() : 그외 경로는 모두 권한이 있어야 가능

.and().csrf()
.ignoringAntMatchers(“/user/login”, “/user/logout”)
로그아웃 하는 경우 csrf 값 무시

.loginPage(“/user/login”).permitAll() : 로그인 경로 모두 접근

.logoutUrl(“/user/logout”)
.logoutSuccessUrl(“/”)
.invalidateHttpSession(true)
.permitAll();

로그아웃 페이지
로그아웃 성공시 이동 Url
세션은 만료 처리
모두 접근 가능

Spring-security 에서는 Auth블라Provider 에서 설정했던 부분이

Spring Boot 로 넘어오면서(?) 아래와 같이 바뀐게 아닌가..?

라는 추측이 든다.

protected void configure(AuthenticationManagerBuilder auth) throws Exception

auth 객체에 userDetailsService 객체를 인자로 갖는 생성자를 호출 할때

MemberService.java -> loadUserByUsername 에서 return 하였던

User의 아이디, 패스워드, 권한을 기준으로 아이디, 패스워드 검증을 하고

아이디와 패스워드가 일치하면 전달 받은 권한을 해당 세션 권한을 부여하는…

그러한 로직이지 않을까..(?)

passwordEncoder() 의 경우 기존 DB 에 암호화처리가 되어 있지 않기 때문에

NoOpPasswordEncoder를 사용하였다.

또는 MemberService.loadUserByUsername 클래스에서

return 값중 password 부분 앞에 {noop} 를 문자열로 추가하여도 된다.


큰 영향을 미치지 않는 Controller.java 와 jsp 파일들..

IndexController.java

@Controller
public class IndexController {
	@RequestMapping("/")
	public String index() {
		return "index";
	}
}

 

UserController.java

@RequestMapping(value = "/user")
@Controller
public class UserController {

	@RequestMapping(value = "userPage")
	public String hello() {
		return "user/userPage";
	}

	@RequestMapping(value = "login")
	public String login() {
		return "user/login";
	}

	@RequestMapping(value = "/logout")
	public String logout(HttpServletRequest request, HttpServletResponse response) {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (auth != null) {
			new SecurityContextLogoutHandler().logout(request, response, auth);
		}
		return "redirect:/";
	}
}

 

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/include/common.jsp"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        <p>Click <a href="/user/userPage">here</a> to see a greeting.</p>
    </body>
</html>

 

/user/login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/include/common.jsp"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <c:if test="${!empty param.error}">
        	<div>
            	Invalid username and password.
            </div>
		</c:if>
		<c:if test="${!empty param.logout}">
			<div>
				You have been logged out.
        	</div>
		</c:if>
		<form action="/user/login" method="post">
			<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
			<div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>

 

/user/logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/include/common.jsp"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
    </body>
</html>

 

/user/userPage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/include/common.jsp"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1>Hello ${request.remoteUser}!</h1>
        <form action="/user/logout" method="post">
            <input type="submit" value="Sign Out"/>
        </form>
    </body>
</html>

 

/include/common.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib  prefix="c"     		uri="http://java.sun.com/jstl/core_rt"%>
<%@ taglib prefix="fmt"    		uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn"     		uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="spring" 		uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form"   		uri="http://www.springframework.org/tags/form"%>
<fmt:requestEncoding value="UTF-8"/>
<%
	response.setHeader("Cache-Control", "no-cache");
	response.setHeader("Pragma", "no-cache");
	response.setDateHeader("Expires", 0);
	request.setCharacterEncoding("UTF-8");
	response.setContentType("text/html; charset=UTF-8");
%>
<%@ page session="true"%>

 

결과화면…

here 클릭..

 

MemberMapper 에서 조회 해 올 수 있는 ID와 password 입력

 

아이디 or 패스워드 다른 경우… parameter 에 error 추가 확인

 

정상적으로 로그인 된 경우.. user/userPage 로 이동된다

Sign Out 클릭시

로그아웃 되면서 메인페이지로 이동 된다.

 

※ 참고
아이디 패스워드를 입력하기전
/user/userPage 입력시 /user/login 페이지로 이동 된다.
(당연한건가…?)

 

참고자료
https://spring.io/guides/gs/securing-web/
https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released
https://github.com/spring-guides/tut-spring-security-and-angular-js/issues/71
https://victorydntmd.tistory.com/328

0 글이 마음에 드셨다면 하트 꾸욱~

카테고리

  • IT (19)
    • Android (1)
    • JAVA (10)
    • jQuery (1)
    • JSTL (1)
    • PHP (3)
    • 기타 (1)
    • 데이터베이스 (1)
      • MSSQL (1)
    • 워드프레스 (2)
  • 리뷰 (1)
  • 이슈 (1)
  • 일상 (44)
    • 나의 일상 (42)
    • 아이들 일상 (1)
  • 잡담 (9)
  • 잡동사니 (4)
  • 취미 (8)
    • NAS (3)
    • 게임 (5)

최근 글

  • [강릉맛집] 콩밀베이커리
  • [강릉맛집] 삼교리동치미막국수 남항진점
  • 2023.05.26 오늘의 메뉴는~ 순대국밥~
  • 2023. 05. 25 점심 메뉴는 또(?) 부대찌개
  • [리팩토링] 첫번째 기록

최근 댓글

  • 프링향 (2020.07.02(목) 불금보다 불타는 목요일 저녁~ 그리고 게임~)
  • 프링향 (2020.07.02(목) 불금보다 불타는 목요일 저녁~ 그리고 게임~)
  • 프링향 (2020.07.02(목) 불금보다 불타는 목요일 저녁~ 그리고 게임~)
  • Brian (2020.07.05(일) 늦은 점심~ 탐나종합어시장)
  • 프링향 (2021년 공휴일…)

다녀가신분

  • 62
  • 80,380
Proudly powered by 워드프레스