<filter>
<!-- BeanIds 에 filter-name 나와있음 -->
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>springSecurityFilterChain</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@Controller
public class LoginProcessServlet {
@Inject
IAuthenticateService service;
@RequestMapping(value="/login/loginProcess.do", method=RequestMethod.POST)
public String doPost(@RequestParam("mem_id") String mem_id
,@RequestParam("mem_pass")String mem_pass
,HttpServletRequest req
,RedirectAttributes redirectAttributes) {
HttpSession session = req.getSession();
Object result = service.authenticate(MemberVO.builder()
.mem_id(mem_id)
.mem_pass(mem_pass)
.build());
if(result instanceof MemberVO) {
// 인증 성공 -> req에 들어있는 정보가 더이상 필요 없음 -> redirect
MemberVO authMember = (MemberVO) result;
session.setAttribute("authMember", authMember);
return "redirect:/";
}else {
String message = null;
if(ServiceResult.NOTEXIST.equals(result)) {
message = "아이디 오류, 그런 사람 없음";
}else if(ServiceResult.INVALIDPASSWORD.equals(result)) { // INVALIDPASSWORD
message = "비번 오류, 다시 입력하셈요.";
session.setAttribute("mem_id", mem_id);
}else { // DISABLE
message = "탈퇴한 회원입니다.";
}
redirectAttributes.addFlashAttribute("message", message);
return "redirect:/login/loginForm.do";
}
}
}
@Controller
public class LogoutServlet{
@RequestMapping(value="/login/logout.do",method=RequestMethod.POST)
public String logout(HttpServletRequest req) throws UnsupportedEncodingException {
HttpSession session = req.getSession();
session.removeAttribute("authMember");
// 로그아웃된것처럼 보임 왜냐 - authMember 하나만 지웠으니까 - 로그인된 중에 세션에 여러가지 정보 저장했을 수도 있음
session.invalidate();
// 모든 어트리뷰트를 하나하나 다 지워주고, 세션 만료시키고, 세션아이디까지 없애줌
String encoded = URLEncoder.encode("로그아웃성공", "UTF-8");
return "redirect:/?message="+encoded;
}
}
private String password; // mem_pass
private final String username; // mem_id
private final Set<GrantedAuthority> authorities; // mem_role
private final boolean accountNonExpired; // 계정 만료
private final boolean accountNonLocked; // 계정 잠금
private final boolean credentialsNonExpired; // 비번만료
private final boolean enabled; // 현재 계정 사용 가능한지? -> mem_delete가 null이면 전부 true, mem_delete가 'Y'면 전부 false
/*
* Security를 위해 UserDetails를 implements하면 간단하지만,
* MemberVO를 사용하던 다른 모듈에서 수정사항이 발생할 수 있으니 adapter패턴을 사용하여 수정사항을 최소화하자
*/
public class MemberWrapper extends User{
public MemberWrapper(MemberVO realMember) {
super(realMember.getMem_id()
, realMember.getMem_pass()
, Collections.singleton(new SimpleGrantedAuthority(realMember.getMem_role())));
}
private MemberVO realMember;
}
<authentication-manager id="authenticationManager">
<!-- provider가 db에서 가져와서 비밀번호까지 비교하는 작업을 함-->
<authentication-provider user-service-ref="customUserService"><!-- authServImpl -->
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
@AuthenticationPrincipal(expression="realMember") MemberVO authMember
이렇게 쓰면 된단다~~~ <annotation-driven validator="validator"><!-- 커스터마이징한 벨리데이터 연결 -->
<argument-resolvers>
<beans:bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver"></beans:bean>
</argument-resolvers>
</annotation-driven>
<form-login
login-page="/login/loginForm.do"
username-parameter="mem_id"
password-parameter="mem_pass"
login-processing-url="/login/loginProcess.do"
always-use-default-target="true"
default-target-url="/"
/>
<!-- security를 타기위해서는 밖에서 다시 filter를 타고 들어와야하는데 탈퇴후 로그아웃할때는 forward로 와서 여길 타지 않음 -->
<logout
logout-url="/login/logout.do"
invalidate-session="true"
logout-success-url="/"
/>
<!-- <intercept-url pattern="/mypage.do" access="isAuthenticated()"/> -->
<!-- <intercept-url pattern="/member/memberList.do" access="hasRole('ROLE_ADMIN')"/> -->
<!-- 비즈니스 로직대상으로 한번더체크하고싶다면 그대로 두어도되지만 컨트롤러단 대상으로 접근제어를 하기위해 servlet-context.xml으로 옮겨놓음 -->
<global-method-security
pre-post-annotations="enabled"
/>
<!-- AOP 활용하여 보호자원 관리 -->
<!-- 컨트롤러에 인터페이스가 없음에도 Interface대상의 proxy가 만들어졌다? -> 그렇다면 실구현체 대상으로 proxy가 만들어지는 설정이 적용되었다는것 (proxy-target-class="true" == cglib 방식 적용됨) -->
<security:global-method-security
pre-post-annotations="enabled"
proxy-target-class="true"
/>
@PreAuthorize("isAuthenticated()")
@Before
처럼 위빙처리@Inject
private AuthenticationManager authenticationManager;
@Override
public ServiceResult modifyMember(MemberVO member) {
ServiceResult result = null;
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(member.getMem_id(), member.getMem_pass()));
int rowcnt = dao.updateMember(member);
if (rowcnt>0) {
result = ServiceResult.OK;
}else {
result = ServiceResult.FAIL;
}
} catch (BadCredentialsException e) { // 비번 오류가 난 상황 (없는 경우 알아서 예외)
result = ServiceResult.INVALIDPASSWORD;
}
return result;
}
<!-- UsernameNotFoundException 살리기 -->
<beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"
p:userDetailsService-ref="customUserService"
p:passwordEncoder-ref="passwordEncoder"
p:hideUserNotFoundExceptions="false"
/>
<authentication-manager id="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="kr.or.ddit.msg.message,org.springframework.security.messages"
/>
org.springframework.context.i18n.LocaleContextHolder
여기에 로케일 정보가 저장되어야한다DispatcherServlet
이 해준다SecurityFilter
가 DispatcherServlet
전에 있다는 것RequestContextFilter
를 사용해라<remember-me remember-me-parameter="rememberMe" remember-me-cookie="rememberMeCookie"/>
<form-login>
의 authentication-success-handler-ref
를 활용AuthenticationSuccessHandler
가 필요하다고함SavedRequestAwareAuthenticationSuccessHandler
이게 우리에게 적합. 이걸 변경해서 쓸 예정
스프링 el기반의 접근제어를 하기위해 use-expression="true"로 설정해놓은것
@PreAuthorize("hasRole('ROLE_ADMIN')")