반응형

 

Windows 에서의 Android Studio에서 발생하는 'unable to find valid certification path to requested target' 에러 해결방법

 

1. Chrome에서 아무 사이트 접속하여 상단의 자물쇠 모양을 마우스 우클릭한다.

2. 이 사이트는 보안 연결(HTTPS)이 사용되었습니다. 클릭

3. 인증서가 유효함 클릭

4.인증서 창에서 상단의 '인증경로'로 접속한후 '맨위의 항목'을 클릭한 다음 '인증서 보기' 클릭

5. 창이 하나 더 나타나며, 상단의 '자세히' 클릭 후 '파일에 복사' 클릭

6. 인증서 내보내기 마법사에서 먼저 다음 누른 뒤 Base 64로 인코딩된 X.509로 바탕화면이든 아무곳에 저장

반응형

7. Android Stuido에서 해당 프로젝트 우클릭 후 Open Module Settings 클릭

8. 좌측 메뉴의 SDK Location 클릭 후 JDK location 확인

'C:\Program Files\Android\Android Studio\jre'

9. C:\Program Files\Android\Android Studio\jre 폴더로 이동 후 bin폴더로 이동

-> C:\Program Files\Android\Android Studio\jre\bin 으로 이동

bin폴더에 keytools.exe가 있음

C:\Program Files\Android\Android Studio\jre\bin 에서 폴더 Windows PowerShell 관리자로 열기

10. keytool 명령어 입력

cacert 파일은 jre\lib\security 폴더에 들어가면 확인할 수 있는데 아래의 명령어를 통해 cacert에 인증서 등록

-file 옵션에는 아까 저장한 인증서 경로를 적으면되고 -alias 옵션을 통해 별칭 저장

또한, 입력하게 되면 패스워드를 입력하라고 하는데 패스워드는 changeit 이다

Password : changeit

.\keytool -import -keystore "C:\Program Files\Android\Android Studio\jre\lib\security" -file "C:\Users\root\Desktop\testcert.cer" -alias testcert

11. 저장 후 안되면 재부팅 또는 Android Studio를 종료 후 다시 실행

반응형
반응형

.

 

Jenkins 에서 Lambda Plugin을 사용한 코드배포 및 함수 실행이다.

 

1. 람다 생성 및 기본적인 플러그인 세팅

1.1) jenkinsTest 람다 함수생성

람다 함수 생성

1.2) Jenkins Lambda Plugin 세팅

젠킨스 플러그인 설치

반응형

2. 파이프라인 세팅

pipeline {
    agent any
    
    stages {
        stage('Git CheckOut'){
            steps{
                git branch: 'main', url: 'https://github.com/ / .git'
            }
        }
        stage('Make .zip'){
            steps{
                zip zipFile: 'test.zip'
            }
        }
        stage('lambda deploy'){
            steps{
                 withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 'pangyeon',
                    accessKeyVariable: 'AWS_ACCESS_KEY_ID', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]){
                    deployLambda(
                        awsRegion: 'ap-northeast-2',
                        awsAccessKeyId: "${AWS_ACCESS_KEY_ID}",
                        awsSecretKey: "${AWS_SECRET_ACCESS_KEY}",
                        functionName: 'jenkinsTest',
                        artifactLocation: 'test.zip',
                        updateMode: 'code'
                    )
                }
            }
        }
        stage('lambda invoke'){
            steps{
                withAWS(region:'ap-northeast-2', credentials:'pangyeon') {
                    invokeLambda(
                        functionName: 'jenkinsTest'
                    )
                }
            }
        }
    }
    post { 
        always { 
            sh 'rm test.zip'
        }
    }
}

 

3. 실행

 

4. 배포 확인

4.1) 이전 코드

이전 코드

4.2) 배포 후 코드

배포 후 코드

5. 실행 확인

5.1) Jenkins 실행 로그

RequestId : d019e541-92df-4fac-9021-96f150b793c2

Jenkins 실행 로그

5.2) Lambda 로그

RequestId :  d019e541-92df-4fac-9021-96f150b793c2

Lambda 로그

5.1, 5.2의 RequestId가 동일하다는 것을 볼 수 있다.

 

반응형
반응형

사내에 Nexus를 구축해서 쓸경우 사내 Nexus Repository에 있는 라이브러리를 가져올 필요가 있는데 이를 위한 세팅 방법이다.

 

.npmrc 나 .yarnrc를 프로젝트 root폴더에 만든다. 우선순위는 .npmrc여서 .npmrc만 만들어서 사용한다.

 

 

//.npmrc
registry=http://nexusUrl.com/repository/npm-public
_auth=id:password // base64 인코딩해야함

 

또는, npm/yarn config 명령어로 global하게 Setting할 수 있다.

Terminal 창에 아래의 명령어를 입력하여 사용.

//npm
npm config set _auth id:password // base64 인코딩해야함
npm config set registry http://nexusUrl.com/repository/npm-public

//yarn
yarn config set _auth id:password // base64 인코딩해야함
yarn config set registry http://nexusUrl.com/repository/npm-public

 

반응형
반응형

Groovy 에서 REST API호출을 위해 HttpBuilder란 것을 사용한다.

아래는 간단히 Groovy에서 Jenkins 빌드를 위한 예제

 

import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON

def http = new HTTPBuilder( 'http://jenkinsUrl.com' )
def crumb =''

http.request(GET) { 
  uri.path = '/crumbissuer/api/json' // CSRF 때문에 먼저 token 호출
  headers.'Authorization' = 'Basic id:paswword' // Base64Encode 해야함
 
  response.success = { resp, reader ->
    crumb = reader['crumb']
  }
 
  
  response.failure = { resp ->
    println 'Error'
  }
}

http.request(POST) {
  uri.path = '/job/test/build' // 빌드할 Jenkins Job
  headers.'Authorization' = 'Basic id:paswword' // Base64Encode 해야함
  headers.'Jenkins-Crumb' = crumb // 위에서 호출한 Token값 필요
 
  response.success = { resp, reader ->
    // 성공하면 젠킨스 빌드됨.
  }
 
  
  response.failure = { resp ->
    println 'Error'
  }
}

 

참조 : https://github.com/jgritman/httpbuilder/wiki

 

GitHub - jgritman/httpbuilder

Contribute to jgritman/httpbuilder development by creating an account on GitHub.

github.com

 

반응형
반응형

다운로드 - https://github.com/wonkwangyeon/Run-Multiple-Program/releases

git source - https://github.com/wonkwangyeon/Run-Multiple-Program

 

처음 회사에서 PC가 처음켜지면 여러 파일을 실행해야해서 일일이 파일 위치 찾아가면서 더블클릭 해가면서 실행하기 불편해서 만든 프로그램.

경로만 입력하고 RUN하면 파일 및 폴더 전부 실행

1. 소개

Windows 전용 파일 및 폴더를 한번에 실행시켜주는 프로그램.

사용언어 - Python

사용 DB - SqlLite

2. 기능

  • 파일 및 폴더 추가 후 프로그램 한번에 실행
  • 추가한 파일 및 폴더 삭제

3. 사용방법

  1. 추가
  • 일반 파일 및 프로그램
    • Select Box에서 File 선택하고 해당 파일 위치와 확장자 입력 후 ADD 버튼클릭
  • 폴더
    • Select Box에서 Folder 선택하고 해당 폴더 위치 입력 후 ADD 버튼클릭
  1. 삭제
  • 삭제할 항목 클릭 후 Delete 버튼 클릭
  1. 실행
  • RUN 버튼으로 실행
  1. 실행 및 실패 로그는 4번의 DB 및 Log경로에서 확인가능

4. DB 및 Log 경로

C:\runMultipleProgram

  • DB.log
    • DB 실행 로그
  • RunMultipleProgram.log
    • 프로그램 시작 로그
  • RunProgramService.log
    • 실행 로그
  • runMultipleProgram.db
    • 추가한 파일 및 폴더를 저장하는 DB

 

다운로드 - https://github.com/wonkwangyeon/Run-Multiple-Program/releases

git source - https://github.com/wonkwangyeon/Run-Multiple-Program

반응형
반응형

 

Window에서 Keycloak 포트 변경을 위해 아래와 같이 입력하였으나

.\standalone.bat -Djboss.socket.binding.port-offset=100

 

실행 시 아래와 같은 에러가 발생하였다.

WFLYSRV0073: Invalid option '.socket.binding.port-offset=100'

 

해결방법은 아래와 같이 옵션 양끝에 쌍따옴표를 붙여 해결 할 수 있다.

.\standalone.bat "-Djboss.socket.binding.port-offset=100"

 

 

반응형
반응형

Sring Security 를 이용하여 JWT를 인증하는 방법이다.

기본적으로 DB연결이 설정 되어 있다는 것과 일반적인 Spring Security Form Login을 알고 있다는 가정하에 시작한다. 되어 있지 않다면 아래의 글을 참고한다.

2021/01/19 - [Develop/Spring Boot] - Spring Boot Security form login

 

Spring Boot Security form login

Spring Boot 에서 Security Form Login 적용 방법이다. 먼저, 간단한 DB, 의존성 세팅과 DB연결 후 Security를 적용한다. 1. 기본 세팅 1.1 DB설정 로그인에 사용할 DB테이블을 먼저 생성한다. CREATE TABLE `user..

wky.kr

 

1. SecurityConfig 생성

SecurityConfig.java 파일을 생성하여 WebSecurityConfigurerAdapter를 상속받고, 아래 3개의 메소드를 Override한다.

 

1. configure(HttpSecurity http) 메소드에서는 Jwt 인증이 실패할 경우 처리할 EntryPoint 설정과 JWT인증에는 기본적으로 세션을 사용하지 않기 때문에 Session을 STATELESS해준다. 또한, JWT인증을 처리할 Filter를 SpringSecurity의 기본적인 필터인 UsernamePasswordAuthenticationFilter 앞에 넣어준다.

 

2. configure(AuthenticationManagerBuilder auth) 메소드는 인증방법을 의미하며,

Spring에서 xml로 Security 설정시 <authentication-manager> <authentication-provider>를 설정하는 것과 같다. 예를 들면 DB에서 사용자 정보를 불러와 현재 입력된 정보와 비교 후 UserDetails 을 반환하여 인증하겠다 라는 의미이다.
현재는 CustomUserDetailSerivce 객체에 인증 방법이 있으며, 패스워드 인코더를 설정해 두었다.

 

3. PasswordEncoder는 로그인시 DB에 BCrpyt로 저장되어있는 패스워드를 로그인할 때 입력한 비밀번호와 비교하기 위해 사용되며, 이는 인증할 때 사용되는 configure(AuthenticationManagerBuilder auth) 메소드에 사용될 것이다.

 

4. AuthenticationManger는 이 글의 뒤에서 나중에 진짜로 인증을 하는 곳에서 사용하기 위해 Bean으로 등록한다.

 

CustomUserDetailService는 이전 글인 Spring Boot Security form login 에서 볼 수 있다.

 

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private JwtAuthenticationFilter jwtAuthenticationFilter;
	
	@Autowired
	private CustomUserDetailService userDetailsService;
	
	@Autowired
	private JwtEntryPoint jwtPoint;
	
	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// TODO Auto-generated method stub
		http
			.csrf().disable()
			.authorizeRequests()
				.antMatchers("/login").permitAll()
				.anyRequest().authenticated()
			.and()
			.exceptionHandling()
			.authenticationEntryPoint(jwtPoint)
			.and()
			.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
			.and()
			.addFilterBefore(
					jwtAuthenticationFilter,
		            UsernamePasswordAuthenticationFilter.class
		        );
	}
	
    @Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// TODO Auto-generated method stub
    	auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}

	@Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
반응형

2. JWT 인증

Filter 생성

요청이 들어올 때 마다 JWT를 인증할 Filter를 생성한다. 요청이 들어올 때마다 하기 위해 OncePerRequestFilter를 상속받는다. OncePerRequestFilter가 아니더라도 일반적인 GenericFilterBean을 상속받아도 무관하다. (OncePerRequestFilter가 이미 GenericFilterBean를 상속받고 있기 때문.)

 

Filter 작동 방식은 간단하다. Bearer로 토큰을 받으면 토큰을 추출하여 올바른 토큰인지 체크를 한다.

토큰이 올바르다면, 토큰에 있는 정보(username, role 등등) 을 가져와 인증을 시킨다.

 

토큰이 없거나, 올바르지않다면 그냥 다음으로 넘어간다.

 

CustomUserDetailService는 이전 글인 Spring Boot Security form login 에서 볼 수 있다.

 

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

	@Autowired
	private JwtProvider jwtProvider;

	@Autowired
	private CustomUserDetailService userDetailsService;

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

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		try {	
			String jwt = getToken(request);
			if (token != null && jwtProvider.validateJwtToken(token)) {
				String username = jwtProvider.getUserNameFromJwtToken(token);

				UserDetails userDetails = userDetailsService.loadUserByUsername(username);
				UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
						userDetails, null, userDetails.getAuthorities());
				authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

				SecurityContextHolder.getContext().setAuthentication(authentication);
			}
		} catch (Exception e) {
			logger.error("Cannot set user authentication: {}", e);
		}

		filterChain.doFilter(request, response);
	}

	private String getToken(HttpServletRequest request){
		String headerAuth = request.getHeader("Authorization");

		if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
			return headerAuth.substring(7, headerAuth.length());
		}

		return null;
	}
}

 

3. JWT Provider 생성

토큰을 인증하거나 생성할 Provider를 생성한다.

generateJwtToken 메소드로 로그인 후 인증에 성공시 토큰을 생성한다.

validateJwtToken 메소드로 토큰이 올바른지 검사한다. 필터에서 이 메소드를 통해 토큰 인증을 진행하고 인증이 성공하면 다음단계로 넘어가고 인증실패할 경우 에러를 호출한다.

getUserNameFromJwtToken 으로 토큰에 포함되어 있는 Body를 추출할 수 있다.

 

@Component
public class JwtProvider {
	
	private static String jwtSecret ="www.wky.krSecretKey";
	private static final Logger logger = LoggerFactory.getLogger(JwtProvider.class);

	private static int jwtExpirationMs =86400000;

	public String generateJwtToken(Authentication authentication) {
		String name = authentication.getName();
		
		return Jwts.builder()
				.setSubject(name)
				.setIssuedAt(new Date())
				.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
				.signWith(SignatureAlgorithm.HS512, jwtSecret)
				.compact();
	}

	public String getUserNameFromJwtToken(String token) {
		return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
	}

	public boolean validateJwtToken(String authToken) {
		try {
			Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
			return true;
		} catch (SignatureException e) {
			logger.error("Invalid JWT signature: {}", e.getMessage());
		} catch (MalformedJwtException e) {
			logger.error("Invalid JWT token: {}", e.getMessage());
		} catch (ExpiredJwtException e) {
			logger.error("JWT token is expired: {}", e.getMessage());
		} catch (UnsupportedJwtException e) {
			logger.error("JWT token is unsupported: {}", e.getMessage());
		} catch (IllegalArgumentException e) {
			logger.error("JWT claims string is empty: {}", e.getMessage());
		}

		return false;
	}
}

 

4. EntryPoint 생성

SecurityConfig에서 등록했던 인증에 실패할 경우 진행될 EntryPoint를 생성한다.

AuthenticationEntryPoint를 implements하여 commence를 작성한다 commence에는 인증이 실패할 경우 넘어갈 URL을 호출하거나 에러메세지를 호출한다.

 

@Component
public class JwtEntryPoint implements AuthenticationEntryPoint {

	private static final Logger logger = LoggerFactory.getLogger(JwtEntryPoint.class);
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException authException) throws IOException, ServletException {
		// TODO Auto-generated method stub
		logger.error("Unauthorized error: {}", authException.getMessage());
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
	}
}

 

5. Login 처리

Login을 직접 처리할 Controller를 생성한다.

LoginVO에는 userId, userPw, token 변수가 선언되어 있다.

프론트에서 userId와 userPw를 JSON으로 전달받아 SecurityConfig에서 Bean으로 등록했던

authenticationManager를 통해 인증을 시도한다. 여기서 인증이 성공되면 다음 코드로 넘어가고

실패하면 SecurityConfig에서 등록한 EntryPoint가 실행된다.

 

성공 후 인증한 객체정보를 가지고 토큰을 생성하고 Token을 반환한다.

반환 객체는 필요한 데이터에 맞게 알맞게 생성하여 반환하면 Token과 함께 반환만 하면 된다.

 

	@PostMapping("/login")
	@ResponseBody
	public ResponseEntity<LoginVO> login(HttpServletResponse response, @RequestBody LoginVO loginVO) {

		Authentication authentication = authenticationManager
				.authenticate(new UsernamePasswordAuthenticationToken(loginVO.getUserId(), loginVO.getUserPw()));

		// SecurityContextHolder.getContext().setAuthentication(authentication);
		String jwt = jwtProvider.generateJwtToken(authentication);
		loginVO.setUserPw("");
		loginVO.setToken(jwt);
		return ResponseEntity.ok(loginVO);

	}

 

 

이러한 작동방식으로 Front에선 Token을 받아 LocalStroage에 Bearer + Token 형태로 저장 후

백엔드로 데이터를 요청할때 LoacalStorage에서 저장한 Token을 꺼내어  Authorization 헤더에 저장한 후 요청한다.

Header : Authorizaion Bearer token

 

번 외

LocalStorage에 저장하여 Header 에 계속 Token을 세팅하기 불편하고 Cookie로 하고싶을 땐 아래와 같이 사용하면 된다.

 

번외 1. Login처리

위에서 사용한 Login처리 Controller에서 Token 생성후 아래와 같이 Cookie에 적용한다.

 

	@PostMapping("/login")
	@ResponseBody
	public ResponseEntity<LoginVO> login(HttpServletResponse response, @RequestBody LoginVO loginVO) {

		Authentication authentication = authenticationManager
				.authenticate(new UsernamePasswordAuthenticationToken(loginVO.getUserId(), loginVO.getUserPw()));

		//SecurityContextHolder.getContext().setAuthentication(authentication);
		String jwt = jwtProvider.generateJwtToken(authentication);
		Cookie cookie = new Cookie("token", "Bearer " + jwt);
		
		cookie.setPath("/");
		cookie.setMaxAge(60 * 60 * 24 * 7);
		response.addCookie(cookie);

		loginVO.setUserPw("");
		loginVO.setToken(jwt);
		return ResponseEntity.ok(loginVO);

	}

 

번외 2. JWT 인증 Filter 생성

위에서 생성한 Filter에 아래와 같이 Cookie에 있는 정보를 가져오는 코드를 작성하여 Cookie에 있는 token을 가져온다.

가져온 뒤의 절차는 위와 동일하다.

 

@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		try {
			String token = Arrays.stream(request.getCookies())
            .filter(c -> c.getName().equals("token"))
            .findFirst()
            .map(Cookie::getValue)
            .orElse(null);
			
			String jwt = getToken(request);
			if (jwt != null && jwtProvider.validateJwtToken(jwt)) {
				String username = jwtProvider.getUserNameFromJwtToken(token);

				UserDetails userDetails = userDetailsService.loadUserByUsername(username);
				UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
						userDetails, null, userDetails.getAuthorities());
				authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

				SecurityContextHolder.getContext().setAuthentication(authentication);
			}
		} catch (Exception e) {
			logger.error("Cannot set user authentication: {}", e);
		}

		filterChain.doFilter(request, response);
	}

	private String getToken(String token){
		String headerAuth = token;

		if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
			return headerAuth.substring(7, headerAuth.length());
		}

		return null;
	}

 

이러한 방식으로 JWT인증을 LocalStorage 뿐만아니라 Cookie를 이용하여 작성할 수 있다.

 

참고 : bezkoder.com/spring-boot-jwt-authentication/

 

Spring Boot Token based Authentication with Spring Security & JWT - BezKoder

Spring Boot JWT Authentication example with MySQL/PostgreSQL and Spring Security - Spring Boot 2 Application with Spring Security and JWT Authentication

bezkoder.com

 

반응형
반응형

Spring 에서 xml을 이용하여 기존의 POST로 진행하는 Login 기능에다가

GET으로 Login진행할 수 있는 기능을 추가하여 사용할 수 있는 방법이다.

(따라서, 일반적인 Form 로그인 방식이 먼저 필요하다.)

2019/11/02 - [Develop/Spring] - Spring security 로그인(DB에 있는 아이디 조회)

 

Spring security 로그인(DB에 있는 아이디 조회)

1. 먼저 필요한 Maven을 설치합니다. 아래의 메이븐저장소에 들어가서 spring-security-core, spring-security-web, spring-security-config, pring-security-taglibs 검색하여 pom.xml에 추가합니다. https://mvn..

wky.kr

 

1. Filter 생성

기존의 Form Login방식은 POST로 데이터를 받기 때문에, Filter를 생성한다.

Username과 Password를 받을 것이기 때문에 UsernamePasswordAuthenticationFilter를 상속받는다.

 

public class GetLoginFilter extends UsernamePasswordAuthenticationFilter {

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		// TODO Auto-generated method stub
		return super.attemptAuthentication(request, response);
	}


}

 

2. Provider 생성

사실 기존에 POST로 로그인하는 기능이 존재하기 때문에 굳이 작성을 하지 않아도 되나, 혹시 GET방식에서 패스워드가 없어도 아이디만 있으면 로그인을 성공시키거나 이러한 기능을 하고 싶다면 생성을 해야한다.

 

public class GetLoginProvider implements AuthenticationProvider {

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean supports(Class<?> authentication) {
		// TODO Auto-generated method stub
		return false;
	}
}

 

3. security xml에 Filter, Provider 등록

3.1 Filter 등록

filter 연결을 위해 class에 위에 생성한 GetLoginFilter를 연결해준다.

 

filterProcessesUrl을 등록해 Get방식으로 Login할 때 어떤 URL을 사용할지 등록한다.

 

name="authenticationManager" 에 기존의 POST방식의 인증을 사용하고 싶다면 ref="org.springframework.security.authenticationManager" 로 사용하면 되나,

여기서는 Provider를 만들었기 때문에 위에서 생성한 Provider를 getLogin이라는 이름으로 등록해 사용할 것이다.

 

인증성공핸들러와 인증실패핸들러는 기존에 이미 사용하고 있던 것이 있기 때문에 기존의 것을 사용해줘도 무관하거나 새로 만들어주어도 상관없다. (현재 글 작성 기준으로 이미 기존의 Form Login 방식이 있는 상태에서 Get Login을 설명하고 있기 때문)

 

postOnly는 Get으로 받을 것이기 때문에 false로 변경한다.

	<beans:bean id="GetLoginFilter" class="net.a.test.login.GetLoginFilter">
		<beans:property name="filterProcessesUrl" value="/getLogin" />
		<!-- <beans:property name="authenticationManager" ref="org.springframework.security.authenticationManager" /> -->
        <beans:property name="authenticationManager" ref="getLogin" />
		<beans:property name="usernameParameter" value="id" />
		<beans:property name="passwordParameter" value="password" />
		<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler" />
		<beans:property name="authenticationFailureHandler" ref="loginFailureHandler" />
		<beans:property name="postOnly" value="false"/>
	</beans:bean>

 

3.2 Provider 등록

위의 Filter에서 Provider를 등록하기 위해 Provider 또한 등록한다.

먼저, 아까 위의 2번에서 생성한 Provider를 bean으로 등록한다.

다음, 다시 등록한 bean을 authentication-manaer로 등록한다.

<beans:bean id="GetLoginProvider" class="net.a.test.login.GetLoginProvider" />

<authentication-manager id ="getLogin">
	<authentication-provider ref="GetLoginProvider" />
</authentication-manager>

 

이렇게 Filter와 Provider를 등록하면 Get 방식으로 인증이 가능해진다.

 

4. Provider 수정

3.1의 Filter 등록의 authenticationManager에서 기존의 인증방식이아닌 새로 생성한 Provider 인증방식을

등록하였기 때문에 2번에서 생성한 Provider를 수정해주어야 한다.

 

기존의 Form Login 기능에 사용하던 userDetailsService와 , PasswordEncoder를 가져온다.

 

authenticate 함수에서 Get 파라미터로 가져온 name과 password를 입력한다.

다음, 기존에 사용하던 loadUserByUsername을 통해 DB에 저장되어있는 암호화된 password와 권한들을 가져온다.

 

그리고 passwordEncoder의 matchs 기능으로 Get파라미터로 가져온 평문의 password와 암호화된 password를

비교해 Passoword가 맞다면 인증을 성공시키고, 다르다면 Exception을 던진다.

public class GetLoginProvider implements AuthenticationProvider {

	@Autowired
	UserDetailsService userDetailsService;
	
	@Autowired
	PasswordEncoder passwordEncoder;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		// TODO Auto-generated method stub
		String name = authentication.getName();
		String password = authentication.getCredentials().toString();
		UserDetails userDetails = userDetailsService.loadUserByUsername(name);

		Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();

		if(passwordEncoder.matches(password, userDetails.getPassword()))
			return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(),
				authorities);
		else
			throw new  BadCredentialsException("authentication failed");

	}

	@Override
	public boolean supports(Class<?> authentication) {
		// TODO Auto-generated method stub
		return authentication.equals(UsernamePasswordAuthenticationToken.class);
	}

}

 

만약, 패스워드입력필요없이 아이디만으로 로그인하고 싶다면 아래와 같이 패스워드 비교 코드를 삭제하고 작성하면 된다.

public class GetLoginProvider implements AuthenticationProvider {

	@Autowired
	userDetailsService userDetailsService;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		// TODO Auto-generated method stub
		String name = authentication.getName();

		UserDetails userDetails = userDetailsService.loadUserByUsername(name);
	
		Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();

		// use the credentials
		// and authenticate against the third-party system
		return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(),
				authorities);

	}

	@Override
	public boolean supports(Class<?> authentication) {
		// TODO Auto-generated method stub
		return authentication.equals(UsernamePasswordAuthenticationToken.class);
	}

}

 

 

이러한 방식으로 기존의 POST로 진행하던 Form Login에서 Get Login 방식을 추가할 수 있다.

반응형

'Develop > Spring' 카테고리의 다른 글

Spring Security URL login  (0) 2021.01.22
Spring Tomcat JNDI 설정  (0) 2020.11.17
Spring Security Custom Filter  (0) 2020.11.09
Spring security 로그인(DB에 있는 아이디 조회)  (0) 2019.11.02
Spring Mybatis + MariaDB(HikariCP) 설정  (0) 2019.10.24
Spring 3 에서 4로 migration  (0) 2019.10.22
반응형

Spring Boot 에서 Security Form Login 적용 방법이다.

먼저, 간단한 DB, 의존성 세팅과 DB연결 후 Security를 적용한다.

 

1. 기본 세팅

1.1 DB설정

로그인에 사용할 DB테이블을 먼저 생성한다. 

CREATE TABLE `user` (
	`id` VARCHAR(50) NOT NULL,
	`pw` VARCHAR(255) NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)

 

1.2 dependency 설정

DB는 현재 MariaDB와 JPA를 사용하며, spring security 의존성과 함께 추가한다.

implementation 'mysql:mysql-connector-java'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'

 

1.3 DB 연결 설정

application.yml(properties) 파일에 DB 연결 정보를 추가 한다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: "jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Seoul"
    username:
    password:
  jpa:
    hibernate:
      ddl-auto: update
    generate-ddl: false
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    properties: 
      hibernate:
        format_sql: true

 

2. JPA 적용

Jpa는 Entity와 Interface로 이루어진 Repository를 생성하면 간단하게 적용할 수 있다.

2.1 Entity 생성

UserVO를 생성하여 생성한 DB테이블에 맞게 VO에 Entity와 Column명 들을 설정한다.

@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "user")
public class UserVO {

	@Id
	@Column(name = "id")
	private String id;
	
	@Column(name = "pw")
	private String pw;
	
	@Column(name = "name")
	private String name;
}

 

2.2 JpaRepository 생성

VO로 생성한 table을 연결할 JpaRepository를 생성한다.

public interface UserRepository extends JpaRepository<UserVO, String> {
	
}

 

3. Security 적용

3.1 WebSecurityConfigurerAdapter 적용

먼저 WebSecurityConfigurerAdapter를 상속받고, 아래 2개의 메소드를 Override하고 Bean을 등록한다.

 

1. configure(HttpSecurity http) 메소드는 기본적인 security 기본 설정을 하는 것이다. 현재는 csrf를 비활성화 시키고,

authorizeRequests()를 이용하여 요청에대한 권한을 처리한다. /login 경로는 권한이 없어도 접속을 허용하고, anyRequest().authenticated()를 통해 이 외의 경로는 권한이 있어야 접속을 허용한다.

formLogin() 을 통해 formLogin을 사용하겠다는 것이며, formLogin 페이지를 만들지 않았다면, Security에서 제공해주는 로그인페이지를 사용한다. 만약 로그인페이지가 있다면. formLogin().loginPage("로그인페이지 경로") 라는 loginPage 옵션을 추가하여 로그인페이지를 커스텀페이지로 변경할 수 있다.

formLogin에는 로그인 성공시 작동할 기능, 실패시 작동할 기능, 로그인 인증 URL 변경 등 다양한 기능들이 있다.

 

2. configure(AuthenticationManagerBuilder auth) 메소드는 인증방법을 의미하며,

Spring에서 xml로 Security 설정시 <authentication-manager> <authentication-provider>를 설정하는 것과 같다. 예를 들면 DB에서 사용자 정보를 불러와 현재 입력된 정보와 비교 후 UserDetails 을 반환하여 인증하겠다 라는 의미이다.
현재는 CustomUserDetailSerivce 객체에 인증 방법이 있으며, 패스워드 인코더를 설정해 두었다.

 

3. PasswordEncoder는 로그인시 DB에 BCrpyt로 저장되어있는 패스워드를 로그인할 때 입력한 비밀번호와 비교하기 위해 사용되며, 이는 인증할 때 사용되는 configure(AuthenticationManagerBuilder auth) 메소드에 사용될 것이다.

 

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private CustomUserDetailService userDetailsService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// TODO Auto-generated method stub
		http
			.csrf().disable()
			.authorizeRequests()
				.antMatchers("/login").permitAll()
				.anyRequest().authenticated()
			.and()
			.formLogin();
	}
	
    @Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// TODO Auto-generated method stub
    	auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}

	@Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

 

3.2 인증을 처리할 메소드

아이디와 비밀번호를 통해 인증을 직접적으로 처리할 메소드이다.

UserDetailsService를 implements하여 loadUserByUsername을 Override한다.

권한을 임의로 생성하였으며,

2번에서 생성한 Repository를 통해 userRepository.findById(로그인아이디)를 사용하여, DB에 저장되어있는 아이디와 비밀번호를 불러온다.

불러온후 security.core에서 제공해주는 User객체를 생성하여 반환한다.

 

configure(AuthenticationManagerBuilder auth)에서 설정한 BCrpyt PasswordEncoder에는 macth라는 패스워드 비교하는 기능이 있는데 User 객체를 반환하면서 현재의 비밀번호와 폼에서 입력한 비밀번호가 match 기능으로 인하여 비밀번호를 비교해주고 비밀번호가 올바르면 로그인 인증 성공으로 처리하고 틀리다면 실패로 처리한다.

import org.springframework.security.core.userdetails.User;

@Service
public class CustomUserDetailService implements UserDetailsService {

	@Autowired
	private UserRepository userRepository;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		
        Collection<SimpleGrantedAuthority> roles = new ArrayList<SimpleGrantedAuthority>();
		roles.add(new SimpleGrantedAuthority("ROLE_USER"));
		
        UserVO userVO =userRepository.findById(username).orElseThrow(() -> new NoSuchElementException());
		return new User(userVO.getId(), userVO.getPw(), roles);
		
	}

}

 

 

이러한 방법을 이용하여, 생성한 DB User테이블에 임의의 ID와 BCrpyt로 암호화한 패스워드를 넣고,

서버를 실행하여 /login 경로로 접속하면, Spring Security에서 기본으로 제공하는 Login Form을 이용하여 로그인을 할 수 있다.

 

반응형
반응형

오프라인 서버에 Nexus가 설치되어 있을 경우, Nexus Repository에 Maven 라이브러리들을 대량 업로드할 필요가 있다.

shell script를 이용한방법과 proxy repository를 이용한 방법이있다.

 

 

1. Shell Script를 이용한 방법.

1.1 mavenimport.sh

아래의 주소에 접속해서 Nexus 설치 서버에 mavenimport.sh를 다운받는다.

github.com/sonatype-nexus-community/nexus-repository-import-scripts

 

sonatype-nexus-community/nexus-repository-import-scripts

A few scripts for importing artifacts into Nexus Repository - sonatype-nexus-community/nexus-repository-import-scripts

github.com

 

1.2 Repository 이동

Window라면 User/.m2/repository에 있는 Maven폴더들을 Nexus가 설치되어 있는 서버에 옮긴다.

아래와 같이 mavenimport.sh와 같은 위치에 라이브러리들을 위치시킨다.

1.3 명령어 실행

넥서스 계정과 비밀번호 및 IP와 PORT 저장할 repository들을 지정하고 실행한다.

./mavenimport.sh -u ID -p PASSWORD -r http://IP:PORT/repository/maven-releases/

실행 후 Nexus 저장소를 확인하면 라이브러리들이 들어가있는 것을 확인할 수 있다.

반응형

2. Proxy Repository를 이용하는 방법

2.1 Local Server 또는 Online Server에 Nexus 설치

인터넷이 되는 서버에 Nexus를 먼저 설치한다.

 

 

2.2 Proxy Repository 생성

Offline으로 Nexus가 설치되어 있는 서버에 maven2 (proxy) 저장소를 생성한다.

생성하는 항목의 Remote storage 부분에 인터넷이 되는 서버의 Nexus Maven Central Repository 또는 이미 사용하고 있는 저장소의 URL을 입력한다.

 

2.3 Settings.xml 설정

Maven Settings.xml을 설정한다 Window일 경우 User/.m2/ 폴더에 있다. 만약 없으면 아래와 같이 생성한다.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">


</settings>

생성하였으면, 아래와 같이 <server> 와 <mirror>를 설정한다.

1. <servers>

<id>에는 <mirror>에 입력할 id 이므로 적절하게 사용한다.

<username>은 Nexus 아이디이다. Nexus에 anonymous가 허용되어있다면 입력해도 무관하다.

<password>는 Nexus 아이디의 비밀번호이다.

 

2. <mirros>

<id> 에는 위에 생성한 id를 입력한다

<name> 은 저장소의 설명이다.

<url> 에는 위에서 생성한 Offline Nexus Server의 maven2 (proxy) URL을 입력하면 된다.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">


 <servers>
    <server>
      <id>nexus</id>
      <username> </username>
      <password> </password>
    </server>
  
  </servers>

  <mirrors>
    <mirror>
      <id>nexus</id>
      <name>nexus</name>
      <url>http://주소:8081/repository/home/</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors>

</settings>

 

설정 후 프로젝트에 Maven Dependency를 추가하거나 Jenkins 빌드를 하게 되면 자동으로 Nexus에 라이브러리들이 업로드되어 Nexus Repository를 사용할 수 있는 것을 확인할 수 있다.

 

끝으로..

2가지 방법 중 하나를 선택해 적절히 사용하면 될 것 같다.

반응형

+ Recent posts