SecurityConfig.java는 Security 설정을 담당합니다.
설명을 드리기에 앞서 전에 web.xml에서 springSecurityFilterChain 을 설정하던 부분이 있습니다.
JavaConfig 설정에서는 이 부분 설정을 다음과 같이 설정을 합니다.
package com.intercast.web.config.security;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends
AbstractSecurityWebApplicationInitializer {
}
이러한 식으로 AbstractSecurityWebApplicationInitializer 을 상속받아 생성해 놓아야 합니다.
그러면 설정완료....^^
그럼 이제 SecurityConfig 파일에 대하여 설명하도록 하겠습니다.
package com.intercast.web.config.security;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import com.intercast.security.access.expression.CustomWebSecurityExpressionHandler;
import com.intercast.security.authentication.CustomAuthenticationFailureHandler;
import com.intercast.security.authentication.CustomAuthenticationSuccessHandler;
import com.intercast.security.service.CustomUserDetailsService;
@Configuration
/*
* @EnableWebSecurity annotation을 반드시 가져야 합니다.
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*
* DB 접속을 통하여 사용자 정보 및 권한을 확인할 Service
*/
@Autowired CustomUserDetailsService userService;
/**
* AuthenticationManager 설정
*
* <security:authentication-manager alias="authenticationManager">
* <security:authentication-provider user-service-ref="userService">
* <security:password-encoder ref="passwordEncoder" />
* </security:authentication-provider>
* </security:authentication-manager>
*
* <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
* <constructor-arg value="256" />
* </bean>
*/
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(new ShaPasswordEncoder(256));
}
/**
* Security 권한체크에 해당하지 않도록 설정을 합니다.
* 해당 항목은 Security 4 에서 부터 적용이 됩니다.
* <security:http pattern="/resources/**" security="none" />
*/
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
/**
* <security:http auto-config="true" use-expressions="true" access-decision-manager-ref="accessDecisionManager">
*
* <security:custom-filter ref="requestProcessingFilter" before="FORM_LOGIN_FILTER" />
*
* <security:intercept-url pattern="/favicon.ico" access="permitAll" />
* <security:intercept-url pattern="/login.htm" access="isAnonymous()" />
* <security:intercept-url pattern="/failureLogin.htm" access="isAnonymous()" />
* <security:intercept-url pattern="/index.htm" access="permitAll" />
* <security:intercept-url pattern="/admsys/**" access="hasRole('SYSADM')"/>
* <security:intercept-url pattern="/**" access="hasCustomRole()" />
*
* <!--
* Security 4에서는 CSRF 설정을 해줘야 합니다. 보안상 처리라고 하는데 사용하지 않는 것으로 처리하였습니다.
* CSRF 사용안함 설정
* -->
* <security:csrf disabled="true"/>
*
* <security:form-login
* login-page="/login.htm"
* login-processing-url="/login/process"
* username-parameter="userId"
* password-parameter="userPass"
* default-target-url="/"
* authentication-success-handler-ref="customeAuthenticationSuccessHandler"
* authentication-failure-handler-ref="customeAuthenticationFailureHandler" />
*
* <security:logout logout-url="/logout.htm" logout-success-url="/login.htm"/>
* <security:access-denied-handler error-page="/accessDenied.htm"/>
* </security:http>
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.accessDecisionManager(accessDecisionManager())
.antMatchers(
"/favicon.ico",
"/index.htm").permitAll()
.antMatchers(
"/login.htm",
"/failureLogin.htm").anonymous()
.antMatchers("/admsys/**"). hasAnyAuthority("SYSADM")
.anyRequest().access("hasCustomRole()")
.and()
.formLogin()
.usernameParameter("userId")
.passwordParameter("userPass")
.loginPage("/login.htm")
.loginProcessingUrl("/login/process")
.successHandler(customAuthenticationSuccessHandler())
.failureHandler(customAuthenticationFailureHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/logout.htm")
.logoutSuccessUrl("/")
.permitAll()
.and()
.exceptionHandling().accessDeniedPage("/accessDenied.htm");
}
/**
* AuthenticationSuccessHandler 설정
* 로그인 실패시 처리되는 Handler입니다.
*
* <bean id="customeAuthenticationFailureHandler" class="com.intercast.security.handler.CustomAuthenticationFailureHandler">
* <property name="defaultFailureUrl" value="/failureLogin.htm" />
* </bean>
* @return
*/
public AuthenticationFailureHandler customAuthenticationFailureHandler() {
CustomAuthenticationFailureHandler handler = new CustomAuthenticationFailureHandler();
handler.setDefaultFailureUrl("/failureLogin.htm");
return handler;
}
/**
* AuthenticationSuccessHandler 설정
* 로그인 성공시 처리되는 Handler입니다.
*
* <bean id="customeAuthenticationSuccessHandler" class="com.intercast.security.handler.CustomAuthenticationSuccessHandler">
* <property name="defaultTargetUrl" value="/index.htm" />
* </bean>
* @return
*/
public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {
CustomAuthenticationSuccessHandler handler = new CustomAuthenticationSuccessHandler();
handler.setDefaultTargetUrl("/index.htm");
return handler;
}
/**
* AccessDecisionManager 설정
*
* Security 설정중 http.authorizeRequests().accessDecisionManager(accessDecisionManager()) 에서 호출합니다.
* 권한 체크에 대한 여러가지 방법 중 AffirmativeBased 사용
*
* <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
* <constructor-arg>
* <list>
* <ref bean="expressionVoter" />
* </list>
* </constructor-arg>
* <property name="allowIfAllAbstainDecisions" value="false"/>
* </bean>
*
* @return
*/
@Bean
public AffirmativeBased accessDecisionManager() {
List<AccessDecisionVoter<?>> voters = new ArrayList<AccessDecisionVoter<?>>();
voters.add(expressionVoter());
AffirmativeBased affirmativeBased = new AffirmativeBased(voters);
affirmativeBased.setAllowIfAllAbstainDecisions(false);
return affirmativeBased;
}
/**
* 사용자 정의 권한을 사용하고자 할 경우 생성합니다.
* WebExpressionVoter에 생성한 권한 설정 Handler을 SET 합니다.
*
* <bean id="customExpressionHandler"
* class="com.intercast.security.handler.CustomWebSecurityExpressionHandler">
* <property name="defaultRolePrefix" value="" />
* </bean>
*
* <bean id="expressionVoter"
* class="org.springframework.security.web.access.expression.WebExpressionVoter">
* <property name="expressionHandler" ref="customExpressionHandler"></property>
* </bean>
*
* @return
*/
@Bean
public WebExpressionVoter expressionVoter() {
WebExpressionVoter voter = new WebExpressionVoter();
CustomWebSecurityExpressionHandler handler = new CustomWebSecurityExpressionHandler();
handler.setDefaultRolePrefix("");
voter.setExpressionHandler(handler);
return voter;
}
}
JavaConfig 를 통하여 Security를 설정할 경우에는 반드시 WebSecurityConfigurerAdapter를 상속받아야 하며
@EnableWebSecurity Annotation을 설정해야 합니다.
또한 AuthenticationProvider을 별도의 Provider로 설정할 수 있으나 나는 아래와 같이 configure(AuthenticationManagerBuilder auth)를 Override 하여 사용하였습니다.
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(new ShaPasswordEncoder(256));
}
그리고 Custom 권한 체크를 위해서 Voter을 생성하고 Handler을 등록 후 사용법을 몰라 한참을 찾다가...ㅡㅡ;;
단순히 access를 사용하여 설정하면 된다는걸.... 알게 되었습니다..ㅡㅡ;;;
이거 땜시 몇시간을 헛수고 했네요..ㅋㅋ
http
.authorizeRequests()
.anyRequest().access("hasCustomRole()")
또한가지..
Spring Security 4.* 로 넘어오면서 또 하나 고생한것이 바로 CSRF 입니다.
이것은 CSRF 공격을 막기 위해 설정하는 부분인데 사용할 경우 Login Form에서 넘길 때 해당 정보도 같이 넘겨줘야 한다고 합니다.
그래서 나는 과감하게 disable() 처리 하였습니다.
처리 하지 않을 시
HTTP Status 403 - Expected CSRF token not found. Has your session expired?
애러가 발생합니다...ㅋ
유의 하시기 바랍니다.
여기까지 XML설정을 JAVA Base로 바꾸는 작업을 하였습니다.
아직 하면서 내공이 부족하여.. 모르고 서핑에서 사용해야 하니까 사용하는 부분이 많은데..ㅜㅜ
더 많은 공부를 해야 한다는 생각이 팍팍 들게 하는 공부였습니다...ㅋㅋ
더군다가 개발을 2년이나 안하고 있던 터라...ㅋㅋ
지금은 PM 겸 PL을 하고 있지만 개발 공부는 끝도 없이 해야 한다는 생각을 합니다..ㅋ
개발을 왜 공부하냐는 분들도 계시지만 전 개발이 좋고 또 PM 또는 PL도 깊이는 아니더라도 이쪽일을 하려면 어느정도는 알고 있어야 한다는 생각을 합니다..ㅋㅋ
저만의 생각일 수도 있겠지만..ㅋㅋ
여튼 그렇습니다..ㅋ
누가 보실지는 모르겠지만 다들 힘내시고 프로그램은 잼납니다...ㅋㅋ
열씨미들 하세요...^^