본문 바로가기
  • A space that records me :)
기술/Spring Security

[Spring security] 인증 및 권한 체크

by yjkim_97 2021. 10. 24.

2021.10.23 - [IT 기술/권한 인증&인가] - [Spring Security] Authentication 라이브러리 구현

 

[Spring Security] Authentication 라이브러리 구현

프로젝트마다 로그인/회원가입/권한인증 등 기능을 매번 구현하기 힘들다. 그래서 직접 프로젝트마다 적용시킬 Authentication 라이브러리를 개발하였다. Authentication 라이브러리는 인증 및 권한 관

yjkim97.tistory.com


8. AuthorizationChecker.java

ignore, permitAll처리 되지 않은 모든 url 요청이 들어오면 AuthorizationChecker를 통해 메뉴 또는 api에 대한 권한 체크를 한다.
해당 url이 메뉴이면 권한그룹 AuthGroup을 체크하고, api이면 역할 AuthRole을 체크한다.

@Component("sufinnAuthorizationChecker")
@RequiredArgsConstructor
public class AuthorizationChecker {

	@Value("${security.login.success.redirect-uri}")
	private String loginSuccessRedirect;
	
	private final AuthCacheManager authCacheManager;
	private final AuthUserService authUserService;
	
	private final AntPathMatcher matcher = new AntPathMatcher();

    public boolean check(HttpServletRequest request, Authentication authentication) {
    	String uri = request.getRequestURI();
    	String method = request.getMethod().toUpperCase();
    	
        Object principalObj = authentication.getPrincipal();
 
        // 로그인 Authentication 확인
        if (!(principalObj instanceof User)) {
            return false;
        }
        
        CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
        
        // 인증여부 확인
        if(ObjectUtils.isEmpty(customUserDetails.getUser())) 
        {
        	return false;
        }
        
       
        if(uri.equals(loginSuccessRedirect))
        {
        	return true;
        }
        
        // url 권한 확인 ============================================================
        List<Integer> authGroupSeqs = new ArrayList<Integer>(); // 보유 권한그룹
        List<String> allRole = new ArrayList<String>(); // 보유한 모든 role (하위 포함)
        this.setAllAuthority(authGroupSeqs, allRole, customUserDetails.getAuthorities());
        
        
        // 메뉴에서 체크
        List<Integer> menuEle = authCacheManager.getCacheUserGroupMenu(uri);
        if(!ObjectUtils.isEmpty(menuEle))
        {
        	for (Integer authGroup : authGroupSeqs) {
        		return menuEle.contains(authGroup);
			}
        	return false;
        }
        
        
        // api에서 체크
        List<String> apiKeys = authCacheManager.getRoleApiKeys();
        String path = String.format("%s%s", method,uri);
        for (String key : apiKeys) {
			if(matcher.match(key, path))
			{
				return allRole.contains(authCacheManager.getCacheRoleApi(key));
			}
		}
        
        return true;
    }
    
    private void setAllAuthority(List<Integer> authGroupSeqs, List<String> allRole, Collection<GrantedAuthority> collection)
    {
    	for (GrantedAuthority authority : collection) {
        	UserGrantedAuthority userAuthority = (UserGrantedAuthority) authority;
        	
        	authGroupSeqs.add(userAuthority.getAuthGroup().getId());
        	this.setChildRoles(allRole, userAuthority.getAuthGroup());
		}
    }
    
    private void setChildRoles(List<String> roleList, AuthGroup authGroup)
    {
    	// role id
    	for(AuthRole ar : authGroup.getAuthRoleList())
    	{
    		if(!roleList.contains(ar.getId()))
    		{
    			roleList.add(ar.getId());
    		}
    	}
    	
    	if(authGroup.hasChlid())
    	{
    		for (AuthGroup cAg : authGroup.getChlidAuthGroupList()) {
    			this.setChildRoles(roleList, cAg);
    		}
    	}
    	
    }
}

 

9. 권한이 없는 사용자 접근시 처리

9-1. HttpAuthenticationEntryPoint.java

spring-security의 AuthenticationEntryPoint 인터페이스를 따른다.
로그인 권한이 없는 경우 spring-security 필터체인은 이곳을 태워 사용자에게 401 응답한다.

public class HttpAuthenticationEntryPoint implements AuthenticationEntryPoint{

	@Autowired
	private MessageProvider messageProvider;
	
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException authException) throws IOException, ServletException {	
		
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, messageProvider.getMessage(AuthConstants.MSG_ERROR_AUTH_FAIL));
	}
}

9-1. HttpAccessDeniedHandler.java

spring-security의 AccessDeniedHandler 인터페이스를 따른다.
권한이 없는 요청을 한 경우 spring-security 필터체인은 이곳을 태워 사용자에게 403 응답한다.

public class HttpAccessDeniedHandler implements AccessDeniedHandler{

	@Autowired
	private MessageProvider messageProvider;
	
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException, ServletException {
		
		response.sendError(HttpServletResponse.SC_FORBIDDEN, messageProvider.getMessage(AuthConstants.MSG_ERROR_PERMISSION_DENIED));
	}
}