반응형

# 환경 정보
스프링 버전 : 4.3.2
시큐리티 버전 : 4.2.3

본 포스팅에서는 커스텀 로그인 페이지 생성 방법을 기록



1. security-context.xml 수정
 - 커스텀 로그인 페이지에 대한 정보를 추가
 - 간단하게 세팅하였고, 예제에 쓰인 설정 값 외에도 여러 세팅값이 있음
1
2
3
4
5
6
7
8
9
10
11
12
<security:http auto-config="true" use-expressions="true">
    <security:intercept-url pattern="/login" access="permitAll"/>
    <security:intercept-url pattern="/*" access="hasRole('USER')"/>
    
    <security:form-login 
        login-page="/login"
        username-parameter="userId"
        password-parameter="userPwd"
        default-target-url="/"
        authentication-failure-url="/login?err=true"
    />
</security:http>
cs
 - login-page : 로그인 페이지 URL
 - username-parameter : username 이라고 써있어 헷갈릴 수 있으나 유저 아이디를 담은 input 태그 name 명.
 - passwrod-parameter : 위와 동일
 - default-target-url : 로그인이 성공한 후 이동할 URL
 - authentication-failure-url : 로그인 실패시 이동할 URL



2. 로그인 페이지 생성

 - 초 단순 로그인 페이지

 - security-context.xml에 설정된 내용에 맞춰 페이지를 만들어준다.

 - login.jsp라는 이름으로 만듬


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
    <h1>커스텀 로그인 페이지</h1>
    <form action="${ctx }/login" method="post">
        아 이 디 : <input type="text" name="userId"/><br />
        비밀번호 : <input type="text" name="userPwd"/><br />        
        <input type="submit" value="로그인"/>
        <sec:csrfInput/>
    </form>
    <c:if test="${param.err }">
        <font color="red">로그인 실패</font>
    </c:if>
</body>
</html>
cs

 - 3 라인

 :: 스프링 시큐리티 태그 라이브러리. 인증된 사용자 정보 접근, csrf 방어 토큰 추가를 간단히 할 수 있게 됨.

 - 12 라인

 :: 로그인 처리를 하는 기본 URL이 post 방식의 /login 이다. 로그인 처리 URL 역시 설정 파일에서 바꿔줄 수 있음

 - 13, 14 라인

 :: 아이디, 비밀번호 입력 태그, name값은 설정 파일에 세팅한대로 해줘야 함

 - 16 라인

 :: csrf 공격 방지용 토큰 추가. 시큐리티4부터 기본값이 csrf 활성화가 되었음.

 - 18 ~ 20 라인

 :: 설정파일에서 로그인 실패시 로그인 페이지에 파라미터 추가한 URL로 이동하도록 세팅해놓았기에 실제로 잘 작동하는지 눈으로 보기 위함




여기까지 한 후 컨트롤러에 /login으로 접근할 수 있게 한 뒤 테스트를 해보면 아래와 같은 화면들을 확인 할 수 있다.


[ 로그인 페이지 접근시 ]




[ 로그인 실패시 ]





[ 로그인 성공시 ]










Posted by NULL..
,
반응형

최근 필요한 것들을 찾다보면 자바 설정 위주의 예제가 많이 나오더라.
MVC프로젝트에서 자바 설정 세팅에 성공한 방법을 포스팅 해둔다
( 자바설정 : web.xml, servlet-context.xml 등 설정파일을 자바 코드로 관리하는 것 )

1. pom.xml 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        <!-- 이것은 기본 세팅값.. 아래의 값으로 변경한다. -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
 
        <!-- 이렇게 고친다. -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
 
cs

기존에 있던 설정을 고쳐주고, 아래의 내용을 추가한다.


1
2
3
4
5
6
7
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>    
cs

web.xml이 없는것을 문제삼지 않겠다는 설정.


1
2
3
4
5
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>
cs

아래 자바 설정파일 만들 때 필요한을 사용하기 위해 필요하다.

정확이 어떤 버전인지는 모르겠으나 프로젝트 생성 기본 버전인 3.1.1에서는 추가가 필요하지만

4.2.3버전 정도에서는 추가하지 않고도 어노테이션을 사용할 수 있다.



2. web.xml을 대신할 자바파일 생성

 - 다음은 프로젝트 생성시 기본적으로 생성되는 web.xml에 포함된 아래의 코드를 자바 코드로 변경한다.


* 기본 web.xml

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
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
 
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
 
<!-- Processes application requests -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
cs

이 코드를.. 아래의 코드로


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class WebInitializer implements WebApplicationInitializer{
 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {        
        
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation("com.post.javaconfig.configuration");
        
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet"new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
        
        
        // 인코딩 필터 적용
        FilterRegistration.Dynamic charaterEncodingFilter = servletContext.addFilter("charaterEncodingFilter"new CharacterEncodingFilter());
        charaterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true"/*");
        charaterEncodingFilter.setInitParameter("encoding""UTF-8");
        charaterEncodingFilter.setInitParameter("forceEncoding""true");
    }    
}
cs

서버 시작시 web.xml이 없으면 WebApplicationInitializer가 구현된 클래스를 알아서 찾아가 세팅을 진행한다.


7번 라인의 설정파일 경로는 설정파일이 모여있을 패키지의 이름을 적어주면 된다.

이렇게 하면 향후에 세팅파일을 만들면 따로 경로추가를 할 필요 없이 알아서 잡아준다.

포스트용 프로젝트의 구조는 아래와 같기에 해당되는 패키지 명을 적어주었다.



그리고 추가적으로, 기본 생성되는 web.xml 파일에는 없지만, 15 - 18번째 줄에 걸쳐 인코딩 필터를 세팅해주었다.



3. servlet-context.xml을 대신할 자바파일 생성

 - 프로젝트 생성시 context.xml 파일이 두개가 자동으로 생성된다. 그 중 root-context에는 아무런 내용이 없기에 패스하고 servlet-context.xml에 들어가 있는 내용을 대신할 자바 파일을 만들어보자.


* 기본 servlet-context.xml

1
2
3
4
5
6
7
8
9
10
<annotation-driven />
 
<resources mapping="/resources/**" location="/resources/" />
 
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>
 
<context:component-scan base-package="com.spring.javaconfig" />
cs

이 코드를 자바코드로 변경하면 아래와 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@EnableWebMvc
@ComponentScan("com.post.javaconfig")
public class ServletConfiguration extends WebMvcConfigurerAdapter{
 
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
    
}
cs

위의 코드와 비교하여 간단하게 설명을 하면


1줄의 @Configuration 은 이 자바 파일이 설정파일이라는 것을 정의하는 어노테이션

2줄의 EnableWebMvc는 xml 파일의 <annotation-driven />

3줄은 따로 설명하지 않는다.


6-7줄은 xml파일의 3번째 줄의 값을 세팅하는 것인데.두 가지 중 한가지만 기록해두었다. 나머지 하나는 아래와 같다.

1
2
3
4
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
cs

두 가지 방법모두 오버라이드 되어 있는데 이를 사용하기 위해서는 WebMvcConfigurerAdapter를 상속해주어야 한다.


11-17줄은 xml파일의 5-8번째 줄에 해당하는 코드이다.




여기까지 세팅을 하고나서 web.xml, root-context.xml, servlet-context.xml 파일을 지우고 서버를 실행하면 정상적으로 실행이 될 것이다.






Posted by NULL..
,
반응형

** mysql이 설치되어있다는 전제로 진행



1. pom.xml 파일에 dependency 추가

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
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>
 
        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
  
        <!-- MyBatis-Spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
 
        <!-- Spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
cs


<version>에 ${org.springframework-version}라고 쓰여 있는 것은

pom.xml 상단에 설정된 프로퍼티를 따르겠다는 것



2. root-context.xml 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="dataSources" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC&amp;useSSL=false"/>
        <property name="username" value="user01" />
        <property name="password" value="1234" />
    </bean>
        
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSources" />
        <property name="configLocation" value="classpath:mybatis/config/mybatis-config.xml" />
        <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml" />
    </bean>
    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
cs


beans 안에 위의 코드를 위치 시킨다. 몇몇 줄에 대한 설명을 첨부한다.

#1. 데이터베이스 구현체.. 프로퍼티로 데이터베이스 정보들을 넣어주어야 함

#3. 데이터베이스 url.. 기본적인 형식은 다음과 같다.

 - jdbc:mysql://[ip]:[port]/[database]?serverTimezone=UTC

 - ip에는 로컬에서 하기 위해 편하게 localhost를

 - port는 mysql 설치시 변경하지 않았으면 3306이다.

 - database는 테스트를 위해 test_db를 생성해두었다

#8. mybatis를 사용하기 위한 팩토리 생성

#10. mybatis 설정 파일의 경로를 지정해준다.

#11. mybatis맵퍼 파일들의 경로를 지정해준다

#14. spring-mybatis를 이용하면 세션관리를 알아서 잘 해준다. 이를 이용하기 위한 설정



3. mybatis xml 파일 생성

 - root-context.xml 을 수정할 때 마이바티스 설정 파일들의 경로를 지정해줬었다. 없으면 에러가 날 것이므로 해당 파일들의 경로 및 파일을 생성해준다.


3-1. 경로 생성 및 파일 생성

 - root-context.xml 수정할 때 [classpath:mybatis/mapper/*.xml]라는 값을 준 적이 있다. 해당 값은 다음의 의미를 가진다.

 [classpath:] : src/main/resources 경로

 [mybatis/mapper/*.xml] : mybatis/mapper/ 아래의 모든 xml파일


 - 아래 첨부한 이미지와 같이 경로와 파일을 생성해준다.


3-2. xml 파일 생성

 - mybatis-config.xml

 - 마이바티스가 제공하는 여러 설정을 지정할 수 있는 파일이다.

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>
    
</configuration>
cs


 - user-mapper.xml

 - sql문을 입력할 파일이다.

1
2
3
4
5
6
7
8
9
10
<?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.security.mysql.dao.UserDao">
 
 
</mapper>
cs

 #7. 맵퍼와 연결할 인터페이스. 혹은 클래스의 경로이다. 자신의 환경에 맞추어 설정하면된다. 본 설정에서는 인터페이스를 이용해 간단하게 이용해 볼 것이다.

4. 데이터베이스에 쿼리 날리기

 - 스프링 프로젝트를 생성하면 기본적으로 설정되는 파일 내에서 테스트를 해볼 것이다.

 - 쿼리 작성을 위해 데이터베이스에 미리 간단한 테이블을 생성해두었다.

 - 내용은 아무것도 넣지 않은 상태이다.

1
2
3
4
5
6
7
8
CREATE TABLE `user` (
    `idx` INT(11NOT NULL AUTO_INCREMENT,
    `user_id` VARCHAR(50NOT NULL,
    `user_pwd` VARCHAR(50NOT NULL,
    PRIMARY KEY (`idx`)
)
ENGINE=InnoDB
;
cs


 - 3번에서 파일 생성을 완료 했다면 디렉토리 구조는 아래와 같을 것이다.


4-1. 쿼리 작성

 - 위에서 생성한 user 테이블에 입력된 데이터 수를 가져오는 쿼리를 만들어 볼 것이다.

 - 쿼리 작성은 인터페이스와 맵퍼 두 파일 모두에서 할 수 있다.

 - 맵퍼 파일을 이용할 경우 여러 옵션 추가나 if문 등도 사용할 수 있다.


 - 인터페이스에서 작성하는 방법은 아래와 같다

1
2
3
4
5
6
public interface UserDao {
    
    @Select("select count(*) from user")
    int getUserCnt();
    
}
cs

 #3. 어노테이션을 이용해 쿼리를 인터페이스에서 바로 작성한다.

 #4. 해당 쿼리를 호출할 메소드명


 - 맵퍼를 이용하는 방법은 인터페이스, 맵퍼파일을 모두 수정해야 한다.

 - UserDao.java

1
2
3
4
5
public interface UserDao {
    
    int getUserCnt();
    
}
cs

 #3. 맵퍼파일의 id를 메소드 이름 설정하고 resultType를 반환값으로 설정


 - user-mapper.xml

1
2
3
4
5
6
7
8
9
<mapper namespace="com.security.mysql.dao.UserDao">
 
    <select id="getUserCnt" resultType="int">
    
        select count(*) from user 
        
    </select>
 
</mapper>
cs

 #3. getUserCnt라는 이름의 select문이고 반환타입은 int이다.

 #5. 쿼리



4-2. 쿼리 호출

 - 4-1에서 작성한 쿼리를 호출해 볼 것이다. 작성방법 두 가지 중에 어떤 것을 사용했더라도 호출 방법은 동일하다. 프로젝트 생성시 기본적으로 만들어지는 HomeController.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
@Controller
public class HomeController {
    
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
    
    @Autowired
    private SqlSession SqlSession;
    
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
        
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
        
        String formattedDate = dateFormat.format(date);
        
        UserDao userDao = SqlSession.getMapper(UserDao.class);
        int userCnt = userDao.getUserCnt();
        System.out.println("userCnt : " + userCnt);
 
        model.addAttribute("serverTime", formattedDate );
      
        return "home";
    }
    
}
cs
- HomeController.java 생성시에 없던 코드는 굵게 표시해두었다.

 #6~7. root-context.xml에 생성해둔 sqlSession을 이용하기 위함

 #18~20. 쿼리 실행한 값을 userCnt에 담고, 받아온 값을 확인하기 위함



여기까지 작성한 후 서버를 실행하고 기본 페이지로 접속을 하면 아래와 같은 내용이 sts 콘솔에 찍힐 것이다.

 



본 글은 간단하게 세팅하는 방법만 기록해두었다.

여러 옵션을 사용하는 방법에 대한 공부가 필요하다..



Posted by NULL..
,