Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 자료구조와 함께 배우는 알고리즘 입문
- 코드로배우는스프링웹프로젝트
- 자료구조와함께배우는알고리즘입문
- 서버설정
- 스프링 시큐리티
- 네트워크 설정
- network configuration
- 알파회계
- GIT
- baeldung
- Kernighan의 C언어 프로그래밍
- 스프링부트핵심가이드
- 데비안
- 이터레이터
- ㅒ
- 티스토리 쿠키 삭제
- iterator
- d
- /etc/network/interfaces
- 구멍가게코딩단
- 코드로배우는스프링부트웹프로젝트
- 목록처리
- 페이징
- 친절한SQL튜닝
- 리눅스
- 처음 만나는 AI수학 with Python
- resttemplate
- 자바편
- 처음 만나는 AI 수학 with Python
- 선형대수
Archives
- Today
- Total
bright jazz music
스프링시큐리티 인 액션 2-3 본문
UserDetailsService와 PasswordEncoder 사용방법 실습한다.
UserDetailsService형식의 맞춤형 빈을 정의해서 스프링 시큐리티에 있는 기본 구성요소를 재정의하는 방법을 배운다,
예제에서는 inMemoryUserDetailsManager를 구현하여 이용함. 이는UserDetailsService보다 복잡하지만 일단 사용함. 이 구현은 메모리에 자격증명을 저장해서 스프링 시큐리티가 요청을 인증할 때에 이용할 수 있게 한다. (실제 운영에는 사용하지 않는다. 예제나 개념 증명 poc 용으로 적합하다. 다른 부분을 구현하지 않아도 된다)
1. 구성 클래스 정의
package com.example.ssiach2ex1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class ProjectConfig {
@Bean //메서드가 반환한 인스턴드를 스프링 컨텍스트에 추가하도록 스프링에 지시
public UserDetailsService userDetailsService() {
// var userDetailsService = new InMemoryUserDetailsManager(); var는 ava11이상부터 가능. var는 구문을 간소화하고 세부 정보를 감춘다.
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
return userDetailsService;
}
}
사용자가 없고, PasswordEncoder가 없어서 엔드포인트에 접근 불가.
1.자격증명(사용자 이름 및 암호)이 있는 사용자를 하나 이상 만든다.
2.사용자를 UserDetailsService에서 관리하고 추가한다.
3.주어진 암호를 UserDetailsService가 저장하고 관리하는 암호를 이용해 검증하는 PasswordEncoder 형식의 빈을 정의
package com.example.ssiach2ex1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class ProjectConfig {
@Bean //메서드가 반환한 인스턴드를 스프링 컨텍스트에 추가하도록 스프링에 지시
public UserDetailsService userDetailsService() {
// var userDetailsService = new InMemoryUserDetailsManager(); var는 ava11이상부터 가능. var는 구문을 간소화하고 세부 정보를 감춘다.
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
//여기까지만 쓰고 구동하면 사용자가 없고, PasswordEncoder가 없어서 엔드포인트에 접근 불가.
//자격증명(사용자 이름 및 암호)이 있는 사용자를 하나 이상 만든다.
//사용자를 UserDetailsService에서 관리하고 추가한다.
//주어진 암호를 UserDetailsService가 저장하고 관리하는 암호를 이용해 검증하는 PasswordEncoder 형식의 빈을 정의
//User클래스는 org.springframework.security.core.userdetails 패키지에 존재하며, 사용자를 나타내는 객체를 만드는 빌더 구현이다.
User user = (User) User.withUsername("john")
.password("12345")
.authorities("read")
.build();
userDetailsService.createUser(user);
//사용자까지 만들었지만 아직 PasswordEncoder가 없음.
//기본 UserDetails서비스를 이용하면 PasswordEncoder도 자동 구성되지만 재정의하면 PasswordEncoder도 다시 정의해야 함.
return userDetailsService;
}
}
$ curl -v -u john:12345 http://localhost:8080/hello
* Trying 127.0.0.1:8080...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to localhost (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'john'
> GET /hello HTTP/1.1
> Host: localhost:8080
> Authorization: Basic am9objoxMjM0NQ==
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400
< Content-Type: text/plain;charset=UTF-8
< Connection: close
<
{ [62 bytes data]
100 62 0 62 0 0 669 0 --:--:-- --:--:-- --:--:-- 681Bad Request
This combination of host and port requires TLS.
* Closing connection 0
package com.example.ssiach2ex1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class ProjectConfig {
@Bean //메서드가 반환한 인스턴드를 스프링 컨텍스트에 추가하도록 스프링에 지시
public UserDetailsService userDetailsService() {
// var userDetailsService = new InMemoryUserDetailsManager(); var는 ava11이상부터 가능. var는 구문을 간소화하고 세부 정보를 감춘다.
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
//여기까지만 쓰고 구동하면 사용자가 없고, PasswordEncoder가 없어서 엔드포인트에 접근 불가.
//자격증명(사용자 이름 및 암호)이 있는 사용자를 하나 이상 만든다.
//사용자를 UserDetailsService에서 관리하고 추가한다.
//주어진 암호를 UserDetailsService가 저장하고 관리하는 암호를 이용해 검증하는 PasswordEncoder 형식의 빈을 정의
//User클래스는 org.springframework.security.core.userdetails 패키지에 존재하며, 사용자를 나타내는 객체를 만드는 빌더 구현이다.
User user = (User) User.withUsername("john")
.password("12345")
.authorities("read")
.build();
userDetailsService.createUser(user);
//사용자까지 만들었지만 아직 PasswordEncoder가 없음.
//기본 UserDetails서비스를 이용하면 PasswordEncoder도 자동 구성되지만 재정의하면 PasswordEncoder도 다시 정의해야 함.
return userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
$ curl -v -u john:12345 https://localhost:8080/hello --insecure
* Trying 127.0.0.1:8080...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to localhost (127.0.0.1) port 8080 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [193 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [155 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [28 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [892 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: C=KR; ST=Some-State; O=Internet Widgits Pty Ltd
* start date: Nov 21 01:17:29 2022 GMT
* expire date: Nov 21 01:17:29 2023 GMT
* issuer: C=KR; ST=Some-State; O=Internet Widgits Pty Ltd
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Server auth using Basic with user 'john'
} [5 bytes data]
> GET /hello HTTP/1.1
> Host: localhost:8080
> Authorization: Basic am9objoxMjM0NQ==
> User-Agent: curl/7.80.0
> Accept: */*
>
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [50 bytes data]
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=409AD2CBAC90032EEFBA3248066C656C; Path=/; Secure; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains
< X-Frame-Options: DENY
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 7
< Date: Tue, 22 Nov 2022 01:01:39 GMT
<
{ [7 bytes data]
100 7 100 7 0 0 113 0 --:--:-- --:--:-- --:--:-- 116Hello!!
* Connection #0 to host localhost left intact
package com.example.ssiach2ex1;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = String.valueOf(authentication.getCredentials());
if("john".equals(username) && "12345".equals(password)) {
return new UsernamePasswordAuthenticationToken(username, password, Arrays.asList());
}else {
throw new AuthenticationCredentialsNotFoundException("Error!");
}
}
@Override
public boolean supports(Class<?> authenticationType) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authenticationType);
}
}
package com.example.ssiach2ex1;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
public class ProjectConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
var userDetailsService = new InMemoryUserDetailsManager();
var user = User.withUsername("john")
.password("12345")
.authorities("read")
.build();
userDetailsService.createUser(user);
auth.userDetailsService(userDetailsService)
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic();
http.authorizeRequests()
.anyRequest().authenticated();
}
}
----------------
package com.example.ssiach2ex1;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import java.util.ArrayList;
import java.util.Arrays;
public class CustomerAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = String.valueOf(authentication.getCredentials());
if("john".equals(username) && "12345".equals(password)){
return new UsernamePasswordAuthenticationToken(username, password, Arrays.asList());
}else {
throw new AuthenticationCredentialsNotFoundException("Error!");
}
}
@Override
public boolean supports(Class<?> authenticationType) {
return UsernamePasswordAuthenticationToken
.class
.isAssignableFrom(authenticationType);
}
}
'Framework > Spring Security' 카테고리의 다른 글
스프링 시큐리티 인 액션 2-1 ~ 2-2 (0) | 2022.11.18 |
---|---|
스프링 시큐리티 설정 (1) | 2022.09.13 |
[Spring security] 1.5 Logout 처리, LogoutFilter (0) | 2022.09.11 |
[Spring security] 1.4 Form Login 인증 필터 : UsernamePasswordAuthenticationFilter (0) | 2022.09.09 |
[Spring security] 1.3 Form Login 인증 (0) | 2022.09.09 |
Comments