
iOS 와 협업을 위해 JAVA/Spring으로 REST API 로 login 기능을 만들고자 합니다. 추후 복습을 위해 공부 과정을 기록하고자 합니다.
공부 중이므로 틀린 내용, 의견, 질문 있으시면 댓글 남겨주시면 감사하겠습니다.

단순 유저 기능만 필요한 시스템까지는 전 단계까지의 과정을 통해 구현 완료 되었습니다. 이번에는 관리자 기능이 필요한 경우에 대해 공부해보고자한다.
학습을 위해 USER/ ADMIN 계정 만들기
package com.ward.ward_server.service;
import com.ward.ward_server.entity.UserEntity;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserService {
private static final String EXISTING_EMAIL = "test@test.com";
private static final String ANOTHER_EMAIL = "next@test.com";
public Optional<UserEntity> findByEmail(String email) {
// TODO : Move this to a database
if (EXISTING_EMAIL.equalsIgnoreCase(email)) {
var user = new UserEntity();
user.setId(1L);
user.setEmail(EXISTING_EMAIL);
user.setPassword("$2a$12$kivpiZrLUW9.44c4P4KpgOrgvH.Y6UkWNP9/nxV5sZW2K5ztE78e6"); // test
user.setRole("ROLE_ADMIN");
user.setExtraInfo("My nice admin");
return Optional.of(user);
} else if (ANOTHER_EMAIL.equalsIgnoreCase(email)) {
var user = new UserEntity();
user.setId(99L);
user.setEmail(ANOTHER_EMAIL);
user.setPassword("$2a$12$kivpiZrLUW9.44c4P4KpgOrgvH.Y6UkWNP9/nxV5sZW2K5ztE78e6"); // test
user.setRole("ROLE_USER");
user.setExtraInfo("My nice user");
return Optional.of(user);
}
return Optional.empty();
}
}
컨트롤러 이렇게 복잡하게 만들지말자. AuthService 만들어서 Service 에서 담당하게 하자.
AuthController는 /auth/login 엔드포인트에서 로그인을 처리합니다.
AuthService를 통해 실제 로그인 처리를 위임합니다.
package com.ward.ward_server.controller;
import com.ward.ward_server.model.LoginRequest;
import com.ward.ward_server.model.LoginResponse;
import com.ward.ward_server.service.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/auth/login")
public LoginResponse login(@RequestBody @Validated LoginRequest request){
return authService.attemtLogion(request.getEmail(), request.getPassword());
}
}
AuthService는 사용자 로그인을 처리하는 서비스입니다.
JwtIssuer를 사용하여 JWT 토큰을 발급합니다.
AuthenticationManager를 사용하여 사용자 인증을 수행하고, 성공한 경우 SecurityContextHolder에 인증 정보를 저장합니다.
인증된 Principal 정보를 사용하여 JWT 토큰을 생성하고, 이를 LoginResponse 객체로 반환합니다.
package com.ward.ward_server.service;
import com.ward.ward_server.model.LoginResponse;
import com.ward.ward_server.security.JwtIssuer;
import com.ward.ward_server.security.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class AuthService {
private final JwtIssuer jwtIssuer;
private final AuthenticationManager authenticationManager;
public LoginResponse attemtLogion(String email, String password) {
var authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(email, password)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
var principal = (UserPrincipal) authentication.getPrincipal();
var roles = principal.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList();
var token = jwtIssuer.issue(principal.getUserId(), principal.getEmail(), roles);
return LoginResponse.builder()
.accessToken(token)
.build();
}
}
AuthController
AuthService
package com.ward.ward_server.controller;
import com.ward.ward_server.security.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class HelloController {
@GetMapping("/")
public String greeting(){
return "Hello, World";
}
@GetMapping("/secured")
public String secured(@AuthenticationPrincipal UserPrincipal principal) {
return "If you see this, then you're logged in as user " + principal.getEmail()
+ " User ID: " + principal.getUserId();
}
@GetMapping("/admin")
public String admin(@AuthenticationPrincipal UserPrincipal principal) {
return "If you see this, then you are an Admin. User ID: " + principal.getUserId();
}
}
"/admin" endpoint 만 하나 추가해서는 ADMIN/USER 구분 없이 다 허용됩니다. 이를 위해 Config 수정해야합니다.
.requestMatchers("/admin/**").hasRole("ADMIN")
한 줄 추가

ADMIN 권한 있어야만 해당 경로 이동 가능합니다. 따라서 USER 계정으로 접근하면 위와 같이 403forbidden이 뜹니다.
Spring Security에서는 주로 역할(권한)을 설정할 때 "ROLE_" 접두사를 사용하는 관례가 있습니다. 따라서 "ROLE_USER"나 "ROLE_ADMIN"과 같이 설정하면, Spring Security는 실제로는 "USER"와 "ADMIN"만을 인식하게 됩니다.