2016년 12월 12일 월요일

98day / Final Project / SPRING Security

http://howtodoinjava.com
오랜만에 수업을!
Security는 조장이 주도해서 프로젝트에 적용하기로 하였으나
일단 수업을 진행하였다. 겨우 30분이지만 졸아버렸다는..

Maven (pom.xml)

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>        
    <artifactId>spring-security-taglibs</artifactId>
    <version>3.2.5.RELEASE</version>
</dependency>  
cs


spring Security 설정 xml

<!-- Spring Security 인증처리로직를 정의한 클래스 -->
<bean name="customizedAuthenticationProvider"
    class="org.kosta.wikipictures.security.MemberAuthenticationProvider" />
    
<!-- Annotation 기반 spring security를 사용하기 위한 설정 -->
<sec:global-method-security secured-annotations="enabled" />
    
<!-- security 적용대상 제외:모든 디렉토리의 js 확장자 파일은 제외하고자 할 때 -->    
<sec:http pattern="/**/*.js" security="none"></sec:http>        
    
    
<!-- 이전페이지 기억하기 위한 Bean -->
<bean id="customLoginSuccessHandler" class="org.kosta.wikipictures.security.CustomLoginSuccessHandler" />
<!-- 
      XML 기반일 경우 아래와 같이 설정할 수 있다 
           
      만약 회원 전용시스템일 경우
      모든 요청에 대해 access = "hasRole('ROLE_MEMBER') 
      또는 access = "hasAnyRole('ROLE_MEMBER','ROLE_ADMIN')" 을 주고 
      특정 서비스에 대해서 모든 사용자에게 접근할 수 있도록 하면 된다 
      <sec:intercept-url pattern="/register.do" access="permitAll" />
  -->
<sec:http use-expressions="true">        
    <!-- <sec:intercept-url pattern="/admin_*" access="hasRole('ROLE_ADMIN')" />
    <sec:intercept-url pattern="/m_*" access="hasAnyRole('ROLE_MEMBER','ROLE_ADMIN')" />        
    <sec:intercept-url pattern="/**" access="permitAll" /> -->
    <!-- 
            login-page : 로그인 페이지 주소를 지정
            username-parameter :  로그인 페이지 form에 있는 username(아이디)의 name
            password-parameter :  로그인 페이지 form에 있는 password의 password
            login-processing-url :  로그인 페이지 form action에 입력할 주소 지정
            default-target-url :  로그인 성공시 이동 주소 
            authentication-failure-url :  로그인 실패인 경우 이동 주소 
     -->
    <sec:form-login  login-page="/auth_error.do"
        login-processing-url="/login.do" authentication-failure-url="/member/login_all_fail.do"
        username-parameter="id" password-parameter="password" 
        authentication-success-handler-ref="customLoginSuccessHandler"/>
    <sec:logout logout-url="/logout.do" logout-success-url="/home.do" />
</sec:http>
    
<!-- 비밀번호 암호화를 위한 설정 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    <!-- <constructor-arg name="strength" value="20"></constructor-arg> -->
</bean>
<sec:authentication-manager>
    <sec:authentication-provider ref="customizedAuthenticationProvider" >        
    </sec:authentication-provider>        
</sec:authentication-manager>    
cs


Security 적용

public class CustomLoginSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler {
    public CustomLoginSuccessHandler() {
    }
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws ServletException, IOException {
        super.setDefaultTargetUrl(request.getHeader("Referer"));
        super.onAuthenticationSuccess(request, response, authentication);
    }
}
public class MemberAuthenticationProvider implements AuthenticationProvider {
    @Resource
    private MemberService memberService;
    // 비밀번호 암호화처리를 위한 객체를 주입받는다
    @Resource
    private BCryptPasswordEncoder passwordEncoder;
    @Override
    /*Authentication authenticate(Authentication authentication) throws AuthenticationException
     * -실제 인증 처리
     *    - 규칙
     *     1. 파라미터로 전달받은 Authentication 객체에 대해 인증처리를 지원하지 않으면 null을 리턴한다.
     *     2. Authentication 객체를 이용한 인증에 실패하면 AuthenticationException 발생시킨다.
     *     3. 인증에 성공하면, 인증 정보를 담은 Authentication 객체를 만들어 return 한다.
     */
    /**
     * 사용자가 화면에서 로그인을 하면 아래의 메서드가 실행된다. 
     * 매개변수 : 인증시 필요한 정보 - Authentication ( 사용자가 입력한 ID , PASSWORD가 저장되어 있음 ) 
     * 리턴 : 인증한 정보를 가진 Authentication     * 
     * 매개변수에 전달된 Authentication객체를 받아 인증처리를 한뒤 인증한 정보를 Authentication에 담아 리턴
     */
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 파라미터로 전달받은 Authentication 객체에 대해 인증처리를 지원하지 않으면 null을 리턴한다.
        if (!supports(authentication.getClass())) {
            return null;
        }
        // 사용자 정보 DB로 부터 조회(UserDetailsService에서 했던 작업)
        String username = authentication.getName();// 사용자가 로그인시 입력한 ID 반환
        MemberVO member = memberService.findMemberById(username);
        if (member == null) {
            throw new UsernameNotFoundException("회원 아이디가 존재하지 않습니다");
        }
        String password = (String) authentication.getCredentials();// 사용자가 입력한
                                                                    // 패스워드 반환
        패스워드 비교
          /* 비밀번호 암호화를 이용할 경우 
         이용자가 로그인 폼에서 입력한 비밀번호와 DB로부터 가져온 암호화된 비밀번호를 비교한다 */
        if (!passwordEncoder.matches(password, member.getPassword()))
            throw new BadCredentialsException("비밀번호 불일치");

        사용자 권한 조회
        List<AuthoritiesVO> list = memberService.selectAuthorityByUsername(username);
        if (list.size() == 0) {
            throw new UsernameNotFoundException("아무 권한이 없습니다.");
        }
        List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
        for (AuthoritiesVO au : list) {
            authorities.add(new SimpleGrantedAuthority(au.getAuthority()));
        }
        /****************************************
         * 여기까지 왔으면 인증 완료 - Authentication객체 생성해서 리턴
         ***************************************/
        Authentication auth = new UsernamePasswordAuthenticationToken(member, password, authorities);
        System.out.println("로그인 OK~" + auth);
        return auth;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        // Class객체.isAssignableFrom(Class객체) 같은 타입의 객체를 담을 수 있는지 체크ㅡ - 둘이 같은
        // class로 부터 생성된 Class객체인지 체크
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
cs

Security를 적용하며 권한과 비밀번호 암호화 관련해서 이슈가 엄청났다.
기존에 VO나 DB쪽에서도 나름 준비한다고 준비했지만 부족함이 많았다.
Security 적용을 위해 DB에서 View까지 고칠 곳이 굉장히 많아 포기한 팀도 많았지만
우리 팀은 조장주도하에 결국 성공했다.(거의 캐리수준)
수료 후에도 지속적인 공부를 해야겠다. 

Related Posts:

  • 84day / Final Project / 아이템 발표 재영이형 미안합니다...죄송... 첫 발표이자 아이템 발표 아이템 발표는 주로 팀소개 아이템 소개 Lean Canvas Mile Stone으로 진행하기로 했지만... 다른 조들은 준비를 너무 잘했다... 하필 폰트도 깨져서 발표자료를 준비한 나는 참 기분이.… Read More
  • 83day / Final Project / Use Case Diagram & ERD & 팀 기조잡기 팀 기조 다시 세우기 일단 어제부로 아이템 확정이 났기 때문에! (감성을 자극하는 오픈소스 프로젝트 Wiki Pictures!) 팀의 방향과 기조 그리고 다양한 Diagram등을 수립해야되는 상황이였다. 허접한 로고를 만들고 우린 비캔버스를 활용하… Read More
  • 82day / Final Project / 아이템 선정 및 Lean Canvas & Mile Stone 아이템 선정 완료! 나의 아이디어가 팀 프로젝트로 선정되었다. 팀원들에게는 미안하지만 이것을 토대로 Lean Canvas와 Mile Stone도 작성하였다. 일단 어제 공부한 것처럼 개발방법론을 도입한다는 것.. 하루 빨리 코딩해야 뭔가 완성될 것 같지만 개발방법… Read More
  • 85day / Final Project / Flow Chart 작성 및 Use Case Diagram 수정 Flow Chart 및 화면단 회의  어마어마한 하루였다. Semi Project 진행시에 진행했던 Flow Chart를 꼭 해야한다고 팀원들에게 건의를 계속 했었고 결국 하게 되었는 데 위와 같이 결과물이 나오는 데 거의 4시간 이상을 소모하였다.… Read More
  • 86day / Final Project / Use Case Diagram과 요구사항정의서 완성 및 ERD작성 완성된 Use Case Diagram Use Case Diagram에 권환 등 수정해야될 부분을 수정하였다 하지만 ERD는..여전히 오리무중이다. 거의 하루의 절반을 ERD에 쏟았는 데 테이블의 조건 등 제약조건이 너무 만만치가 않다 개인 ERD 저번에는… Read More

0 개의 댓글:

댓글 쓰기