https://github.com/kkimsungchul/study/tree/master/Spring%20Boot/SpringSecurity
https://github.com/kkimsungchul/sungchul_ETC/tree/main/src/main/java/com/sungchul/etc/config
구글링으로 참고한 여러 소스들을 가져다 사용했음
일단 복붙으로 작성하고 내가 원하는 부분만 커스터마이징 했기 때문에 정확히 어떻게 작동하는지에 대해 한번 서술하면서 정리할 필요를 느낌
다 적용하고 나니 간단하긴 한데.. 처음이라 그런지 살짝 복잡한 느낌이 들긴함
SpringSecurity
csrf
CSRFController.java
jwt
config
JwtAuthenticationEntryPoint.java
JwtRequestFilter.java
JwtUserDetailsService.java
controller
JwtAuthenticationController.java
util
JwtTokenUtil.java
vo
JwtRequest.java
JwtResponse.java
security
CustomUserDetailsService.java
SecurityConfig.java
UserContext.java
WebSecurityConfig.java
SwaggerConfig.java
[ SpringSecurity 적용 ]
## CustomUserDetailsService.java
org.springframework.security.core.userdetails.UserDetailsService 인터페이스를 구현함
DB에서 사용자의 정보를 가져 오는 부분이며, 입력받은 ID로 사용자의 정보를 조회해서 "UserContext" 클래스에 담아서 리턴해주는 역할을 함
## SecurityConfig.java
스프링시큐리티의 설정파일
어떤 유저가 어떠한 권한이 있는지 체크하고,
비밀번호 암호화를 할 수 있도록 암호화 객체를 제공해줌
또한 인증없이 접근이 가능한 URL을 설정 할 수 있으며,
특정URL에는 특정 권한을 가지고 있는 사용자만이 접근 할 수 있도록 설정할 수 있음
※ WebSecurityConfig.java 파일을 작성하면서 위에 내용들을 전부다 주석처리하였음
※ 위의 내용은 WebSecurityConfig.java 파일에 포함되어있음
## UserContext.java
org.springframework.security.core.userdetails.User 를 상속받아서 구현함
넘겨받은 값들을 부모클래스의 생성자에 넣어줌
사용자의 ID , 비밀번호, 권한을 넣어줌
여기서 넣어준 첫번째 인자값은 꺼내서 사용할 떄 userDetails.getUsername(); 로 꺼내서 사용함
[ JWT 적용 ]
- config 패키지
## JwtAuthenticationEntryPoint.java
허가되지 않은 사용자라면, 접근 불가 메세지를 띄워 리소스 정보획득을 못하게 막아줌
해당 클래스는 "WebSecurityConfig.java" 파일에서 아래와 같이 선언하여 사용하며.
=================================================================================================================
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
=================================================================================================================
"WebSecurityConfig.java" 파일에서 configure 메소드에서 httpSecurity 에 "authenticationEntryPoint" 옵션에 적용함
다만 해당 옵션 적용 시 springSecurity의 기본 로그인 페이지를 사용 할 수 없음
해당 옵션을 적용하면 허가되지 않은 페이지 접근시 401오류가 발생하지만,
적용하지 않는다면 springSecurity의 html 페이지가 로드됨
=================================================================================================================
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
=================================================================================================================
## JwtRequestFilter.java
프론트에서 request 를 요청할때마다 해당 필터를 거치도록 해야함
해당 필터는 header에 담겨 있는 토큰 정보가 유효한지 확인하는 클래스임
=================================================================================================================
final String requestTokenHeader = request.getHeader("jwt")
=================================================================================================================
위와 같이 헤더에 저장된 값을 꺼내오는 역할을 함
## JwtUserDetailsService.java
위에서 Springsecurity 만 사용할 때 작성한 클래스 "CustomUserDetailsService.java" 와 똑같이 구현하였음.
여기서도 똑같이 UserContext.java 클래스를 리턴해줌
- controller 패키지
## JwtAuthenticationController.java
사용자의 인증 요청 처리를 담당할 컨트롤러임
사용자가 보내온 ID / PW 를 가지고 인증처리를 담당함
authenticate 메소드를 통해서 사용자가 입력한 ID / PW 를 통해 사용자를 인증함
오류가발생할 경우 Exception 을 띄움
UserDetails클래스의 loadUserByUsername메소드에서 리턴받은 값을 가지고
JwtTokenUtil 클래스의 generateToken 메소드를 통해 사용자의 토큰을 발급해줌
- util 패키지
## JwtTokenUtil.java
JWT 토큰을 사용할 수 있도록 여러가지 기능들을 구현한 클래스
토큰에 저장된 사용자의 ID , 토큰에 저장된 만료일, 토큰이 만료되었는지, 토큰발급등의 로직을 처리함
- vo 패키지
## JwtRequest.java
VO임. 사용자가 입력한 ID / PW 를 받아오는 역할을 함
## JwtResponse.java
요청에 대한 응답 객체임.
사용자가 ID / PW를 입력하여 요청을 보냈을때, 해당 클래스에 값을 담아서 사용자에게 되돌려줌
-security 패키지
## WebSecurityConfig.java
해당 파일은 "SecurityConfig.java" 에서 구현한 내용과 비슷하지만, "JwtAuthenticationEntryPoint" , "JwtRequestFilter" 두개의 클래스를 주입받아서
매 요청시 "JwtRequestFilter" 가 작동할 수 있도록 구현, 사용자의 인증 정보가 잘못되었을 경우 "JwtAuthenticationEntryPoint" 를 호출하도록 구현하였음
=================================================================================================================
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
=================================================================================================================
-application.yml 파일
@value로 꺼내서 사용할 값을 기재
=================================================================================================================
spring :
jwt:
secret : jwtsecretkey
=================================================================================================================
[ Swagger 에 JWT 적용 ]
## SwaggerConfig.java
"JwtRequestFilter" 를 구현함으로써 스웨거UI와 로그인을 제외한 요청에 대해서 JWT 토큰을 검증하도록 하였음
헤더값에 매번 jwt 토큰을 넣어 줄 수가 없으니, 스웨거의 authorize 기능을 확용하기로 함
기존에는 api() 메소드에서 빌드 부분에 security 관련 설정을 넣지 않았지만, 여기서는 추가하였음
=================================================================================================================
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.securityContexts(Arrays.asList(securityContext()))
.securitySchemes(Arrays.asList(apiKey()));
}
=================================================================================================================
apiKey() 메소드에서는 apikey의종류, key의 이름, 포함되어 있는 곳에대한 정보를 입력함
=================================================================================================================
private ApiKey apiKey() {
return new ApiKey("JWT", "jwt", "header");
}
=================================================================================================================
그리고 아래의 옵션은 뭐 잘 모르겟음...
SecurityContext메소드는 호출되면 defaultAuth() 에서 받아온 값을 넣어서 생성하는것으로 보이고
defaultAuth 메소드는 적용 범위와 어떠한 인증 방식을 사용할지 (JWT , Authorization) 를 정하는 것으로 보인다.
=================================================================================================================
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(defaultAuth()).build();
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Arrays.asList(new SecurityReference("JWT", authorizationScopes));
}
=================================================================================================================