블로그 이미지
박공명

카테고리

분류 전체보기 (99)
된장 (7)
Dev (60)
꼐..꼐임 (6)
식탐 (18)
우리 (0)
Etc (8)
개인자료 (0)
Total
Today
Yesterday

Spring Security 를 적용하기위한 Filter를 등록한다.


  <filter>

    <filter-name>springSecurityFilterChain</filter-name>

    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

  </filter>

  <filter-mapping>

    <filter-name>springSecurityFilterChain</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>


관련 설정을 저장할 xml파일을 Context에 추가등록한다. 

내껀 Context-* 이기때문에 변경할게 없다.

일부 설명은 발췌


<intercept-url pattern="/login" access="permitAll" />

<intercept-url pattern="/-" access="hasRole('ROLE_USER')"/>

<form-login login-page="/login" username-parameter="username" password-parameter="password" login-processing-url="/authentication" />

 

login-page : 로그인이 요청될 시에 이동할 URL을 설정합니다.

username-parameter : 로그인 아이디의 파라미터명 즉 name필드값을 설정합니다.

passoword-parameter : 비밀번호의 파라미터 명을 설정합니다.

login-processing-url : 폼에서 전송할 URL 값을 설정합니다. (action=login-processing-url)

 

여기서 주의할 점은 로그인 URL 인터셉터를 모든 리소스를 차단하는 인터셉터의 위쪽으로 배치시켜야 한다는 것입니다. 만약 그렇지 않다면 리디렉션 순환 오류로 정상적인 로그인 창이 뜨지 않으실 겁니다

<logout invalidate-session="true" logout-url="/unAuthentication" logout-success-url="/" />


invaldate-session : 세션을 모두 무효로 할 것인지를 사용자에게 묻습니다.

logout-url : 로그아웃 경로를 설정합니다.

logout-seccess-url : 로그아웃이 성공한 뒤에 이동한 경로를 설정합니다.


가장만저 만들어야할게 로그인을 위한 jdbcManager를 만들어줘야한다.

만든다는 개념보다는 상속받아 필요한부분을 추가한다.

기존 org.springframework.security.provisioning.JdbcUserDetailsManager 를 사용하고있었는데

salt관련 처리가 없다 그렇기때문에 SaltedUserDetailsManager 란 클래스를 만들어서 해당클래스를 상속하였다.


public class SaltedUserDetailsManager extends JdbcUserDetailsManager

{

private static final Logger logger = LoggerFactory.getLogger(SaltedUserDetailsManager.class);

    public UserDetails loadUserByUsername(String userId)

    {

        final List<GrantedAuthority> groupAuthorities = super.loadGroupAuthorities(userId);

        for(GrantedAuthority authority : groupAuthorities)

        {

            logger.info("user authority : {} ",authority.getAuthority());

        }


        UserDetails user =  getJdbcTemplate().queryForObject(

                super.getUsersByUsernameQuery(),

                new String[]{userId},

                new RowMapper<UserDetails>(){

                    public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException

                    {

                        String userId = rs.getString(1);

                        String password = rs.getString(2);

                        boolean enabled = rs.getBoolean(3);

                        String salt = rs.getString(4);

                        logger.info("user id : {} ",userId);

                        logger.info("user pw : {} ",password);

                        logger.info("user useable : {} ",enabled);

                        logger.info("user salt : {} ",salt);

                        return new SaltedUser(userId, password, enabled, true, true, true, groupAuthorities, salt);

                    }

                }

            );

        return user;

    }

}


이러면 기존 org.springframework.security.core.userdetails.User 타입을 반환하게 되있는데 역시 salt가 없다.

당연히 추가해야한다.


public class SaltedUser extends User

{


    private String salt;

    public SaltedUser( String username, 

    String password, 

    boolean enabled, 

    boolean accountNonExpired, 

    boolean credentialsNonExpired, 

    boolean accountNonLocked, 

    Collection<? extends GrantedAuthority> authorities, 

    String salt)

    {

        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);

        this.salt = salt;

    }


    public String getSalt()

    {

        return salt;

    }

    public void setSalt(String salt)

    {

        this.salt = salt;

    }

}


이거면 로그인에필요한 자바쪽 작업은 끝났다.

context에 bean을 추가해준다.

쿼리는 컬럼명이중요한게 아니라 순서가 중요한거다. 이정돈 알겟지?

사실나는 별생각없이 적용했기때문에 테이블쪽 설계를 안햇다. 그래서 1개테이블로 그룹없고 권한단순하게 일단했다.

근데 enableGroups 옵션을 false해도 자꾸 에러나길래 봣더니 기존 default쿼리를 때리고있었다. 

안써도 일단 추가햇다.


    <bean id="jdbcUserService" class="kr.iwallet.SaltedUserDetailsManager"

        p:dataSource-ref="dataSource"

        p:enableGroups="false"

        p:usersByUsernameQuery="SELECT ID , PWD, ENABLED, SALT FROM USER_TABLE WHERE ID=?"

        p:authoritiesByUsernameQuery="SELECT ID AS USERNAME, ROLE AS AUTHORITY FROM USER_TABLE WHERE ID=?"

        p:groupAuthoritiesByUsernameQuery="SELECT ID , PWD, ENABLED, SALT FROM USER_TABLE WHERE ID=?"

     />


그리고 encoder와 salt쪽 설정을 추가한다.

userPropertyToUse 가 salt 인이유는 소스를 함 열어봐라. 내가위에서 Users를 왜 상속해서 새로만들었는지 알수있다.


<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">

<property name="userPropertyToUse" value="salt"/>

</bean>

<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />


마지막으로 해당 bean들을 사용할수있게 세팅.


    <security:authentication-manager>

        <security:authentication-provider user-service-ref="jdbcUserService">

            <security:password-encoder ref="passwordEncoder">

                <security:salt-source ref="saltSource"/>

            </security:password-encoder>

        </security:authentication-provider>

    </security:authentication-manager> 

이럼 password와 salt 컬럼의값을 더하고 암호화한값을 db의 password와 비교하게된다.

사용자를 추가하거나 수정할때는 암호화를하고 salt를 넣어야겟지?

salt는 임의의 랜덤한 값을 넣게되는데 나는 생성 수정당시의 시분초를 넣었다.

그래서 이렇게 암호화하면 끝


String encodePassword = passwordEncoder.encodePassword(pw,salt);







 

Posted by 박공명
, |

세상에 공짜보다 좋은게 없으므로

스프링 프레임워크를 사용한 웹페이지에 네이버 스마트 에디터를 적용하도록 하겟다.

사실 에디터 적용은 잭스도 할수있는일이니 사진 퀵 업로더가 주 내용이다.

나는 개발서버에서의 에디터 위치를 /resource/SE 로 설정하였다.

사실 플러그인 설치와 버튼 추가는 설명도 잘 되있을 뿐더러

이미 적용되어 있더라 ㅡ,.ㅡ 손댈것이 없다.

업로드용 javascript를 수정해야한다.

 

/resource/SE/photo_uploder/popup/attach_photo.js

 

callFileUploader 이건 html5를 사용하지않는 업로드용이라는데 이걸 기준으로 해보겠다.

request를 전송할 주소를 만들어준다.

나는 아래와같은 주소로 POST 형식으로 파일을 받을거다.

sCallback은 스프링에서는 지워줘도 될거같다.

놔둬봐야 쓸모업는 페이지 한번 더읽는거같다.

 

sUrl  : 'http://localhost:8080/web/imageUpload.gm'

 

파일업로드를하는데 대체 어디다 담아올릴건지 확인을 안했다.

사진업로드할때 나오는 팝업인 photo_uploader.html 파일을 살펴보면 Filedata 라는 이름을 찾을수 있다.

이 이름으로 파일을 받아서 저장하고해야하며 또 중요한건 파일을 올릴때 별도의 콜백함수이름을 같이 보내준다는거다.

결론은 파일이름,콜백함수명 두개를 화면으로 다시 가져와야한다.

나는 callBack.jsp 를 새로 만들었다.

 


 @RequestMapping(value = "/imageUpload.gm", method = RequestMethod.POST)
 public String writeBoard(Locale locale, Model model,HttpServletRequest request) {
  logger.info("Welcome imageUpload!! The client locale is {}.", locale);
  
  String filename = "";
  String filenameFront = "";
  String filenameExt = "";
  String convFilename = "";
  FileSystemResource uploadDir = new FileSystemResource("E:/APPLICATION/STC/vfabric-tc-server-developer-2.9.3.RELEASE/base-instance/wtpwebapps/gm_spring_mvc/resources/uploadimages/");
  
  MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request;
  MultipartFile file = multipart.getFile("Filedata");
  String callBack = multipart.getParameter("callback_func");
  if(!file.isEmpty()) {
   
   filename = file.getOriginalFilename();
   filenameFront = filename.substring(filename.lastIndexOf("."));
   filenameExt = filename.substring(filename.lastIndexOf("."),filename.length());
   //convFilename = Tool.getCurrentDayTimeMill() + filenameExt;
   convFilename = "";
   logger.info("OriginalFilename : {}", filename);
   logger.info("OriginalFilename front : {}", filenameFront);
   logger.info("OriginalFilename ext : {}", filenameExt);
   logger.info("uploadDir : {}", uploadDir.getPath());
   
   try {
    if(file.getSize() > 0){
     File out = new File(uploadDir.getPath() + "/" + Tool.getCurrentDayTimeMill() + filenameExt);
     FileCopyUtils.copy(file.getBytes(), out);
     convFilename = out.getName();
     logger.info("ConvertFilename : {}", convFilename);
    }
   } catch (IOException e) {
    e.printStackTrace();
   }
  
  }

  model.addAttribute("filename", convFilename);
  model.addAttribute("callback_func", callBack);

  return "/util/callback";
 }

 

이러면 파일이 저장된 후 파일이름과 콜백함수명을 callBack.jsp로 뱉어준다.

기존 에디터 샘플에있는 callBack.html 을 내jsp경로(/util/)로 옮겨주고 일부 내용만 수정해준다.

 

var oParameter = {callback_func:"${callback_func}",sFileName : "${filename}",sFileURL : "http://localhost:8080/web/resources/uploadimages/${filename}",bNewLine : true }; // query array

 

뭐 더이상의 설명은 생략한다.

결과물.

 

 

 

 

Posted by 박공명
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함