728x90
반응형
Redis 관련 설정 포스트 :
2021.08.27 - [Spring/Reids] - [Spring Redis-Session] Spring Redis Session With Docker
Interceptor 간단한 예제 포스트 :
2021.08.27 - [Spring] - [Spring Interceptor] 커스텀 어노테이션과 Intercepter 구현
모델 추가
- User
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
}
- SessionMember : 세션 이용에서 직렬화/역직렬화를 위해 User의 Dto 역할을 하는 클래스를 따로 둔다.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SessionMember implements Serializable {
private String name;
private int age;
}
커스텀 어노테이션 추가
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Auth {
}
인터셉터 추가
@Slf4j
@Component
public class SessionAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//어노테이션 체크 - Controller에 @Auth 어노테이션이 있는지 확인
boolean hasAnnotation = checkAnnotation(handler, Auth.class);
if (hasAnnotation) {
//어노테이션이 있으면서, User의 정보가 맞다면 true 반환
//request에서 session 받아오기
HttpSession session = request.getSession();
SessionMember sessionMember = (SessionMember) session.getAttribute("sessionMember");//sessionMember객체로 저장된 객체 반환
String userName = sessionMember.getName();
Integer userAge = sessionMember.getAge();
log.info("userName, userAge : {}, {}", userName, userAge);
//User의 정보는 DB에서 불러오지만, 여기서는 간단히 하기 위해 임의의 값으로 확인
// walter와 20이 세션정보에 있을 때 권한이 있는것으로 가정
if (userName.equals("walter") && userAge.equals(20)) {
return true;
}
throw new AuthException();
}
//Auth를 실패하더라도 Controller를 실행하기 위해서는 true로 설정해야한다. ex)/session/add의 경우 walter/20 이 아닌 다른 값이 들어가도 실행되어야 한다.
return true;
}
private boolean checkAnnotation(Object handler, Class<Auth> authClass) {
//js. html 타입인 view 과련 파일들은 통과한다.(view 관련 요청 = ResourceHttpRequestHandler)
if (handler instanceof ResourceHttpRequestHandler) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
//Auth anntotation이 있는 경우
if (null != handlerMethod.getMethodAnnotation(authClass) || null != handlerMethod.getBeanType().getAnnotation(authClass)) {
return true;
}
//annotation이 없는 경우
return false;
}
}
예외 처리 설정
- @RestControllerAdvice로 전역 예외처리 가능
public class AuthException extends RuntimeException{
public AuthException(){
super(HttpStatus.UNAUTHORIZED.toString());
}
}
@RestControllerAdvice
public class ExceptionAdviceHandler {
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(AuthException.class)
public ResponseEntity authException(walter.unit.interceptor_reids_session.exception.AuthException e){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("권한이 없습니다. " + e.getLocalizedMessage());
}
}
인터셉터 설정
@RequiredArgsConstructor
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
private final SessionAuthInterceptor sessionAuthInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sessionAuthInterceptor).addPathPatterns("/session/*");
}
}
Controller
@Slf4j
@Controller
public class SessionInterceptorController {
@GetMapping("/session")
public String index(){
return "sessionAdd";
}
@PostMapping("/session/add")
public ResponseEntity add(@RequestBody User user, HttpSession session){
log.info("user: {}", user);
SessionMember sessionMember = new SessionMember();
sessionMember.setName(user.getName());
sessionMember.setAge(user.getAge());
session.setAttribute("sessionMember", sessionMember);
return ResponseEntity.ok().body("session add");
}
@Auth
@GetMapping("/session/auth")
public String sessionAuth(HttpSession httpSession, Model model){
model.addAttribute("userData", (SessionMember)httpSession.getAttribute("sessionMember"));
return "sessionResult";
}
@GetMapping("/session/non-auth")
public String sessionNonAuth(HttpSession httpSession) {
return "sessionResult";
}
@GetMapping("/session/logout")
public String logout(HttpSession httpSession){
httpSession.invalidate();
return "sessionAdd";
}
}
View
- Mustache 이용
- sessionAdd.mustache
<html>
<head>
<title> 세션 추가 페이지 </title>
</head>
<body>
<form>
name : <input type="text" id="name">
age : <input type="text" id="age">
<input type="button" id="submitButton" value="추가">
</form>
</body>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="/js/add.js"></script>
</html>
- sessionResult.mustache
<html>
<head>
<title> 세션 유저 정보 확인 페이지 </title>
</head>
<body>
{{#userData}}
userName : {{name}} <br>
userAge : {{age}}
{{/userData}}
<!-- userData가 없을 때 ex)/session/non-auth -->
{{^userData}}
유저 정보가 없습니다.
{{/userData}}
</body>
</html>
- add.js
var add = {
init:function(){
var _this = this;
$('#submitButton').on('click', function(){
_this.submit();
});
},
submit:function(){
var user = {
name : document.getElementById("name").value,
age : document.getElementById("age").value
};
$.ajax({
type: 'POST',
url: '/session/add',
dataType: 'text',
contentType:'application/json; charset=utf-8',
data: JSON.stringify(user),
success:function(data){
console.log("성공");
window.location.href="/session/auth";
},
error:function(e){
console.log("실패");
alert(e.status);
}
});
},
};
add.init();
테스트
- http://localhost:8080/session 에서 name, age 전송 => 로그인 로직을 단순화시켜 walter, 20을 넣으면 통과하도록 인터셉터 로직이 되어 있다.
- [reids] flushall : 모든 데이터 지우기
- [browser] name, age 폼 입력 후 추가
- http://localhost:8080/session/auth 접속 시
- testuser / 10 => 예외 발생
- [redis] keys *
- [browswer]
- walter / 20 => 성공 => 결과화면
- [browser] localhost:8080/session => walter / 20 입력
- [redis] keys * => 세션 정보가 업데이트된다.
- [browser] Intercepter를 성공적으로 통과
- testuser / 10 => 예외 발생
- http://localhost:8080/session/logout
- redis에 key 출력 => 세션정보 삭제 확인
Github : https://github.com/twer4774/interceptor_reids_session
파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
반응형
'Spring > Redis' 카테고리의 다른 글
[Spring Redis-Session] Spring Redis Session With Docker (0) | 2021.08.27 |
---|