Skip to content

Commit

Permalink
feat($api-portal): use remote service; enhance web security exception…
Browse files Browse the repository at this point in the history
… handling
  • Loading branch information
johnnymillergh committed May 11, 2020
1 parent 8aca3d0 commit d80b182
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.jmsoftware.apiportal.remoteapi;

import com.jmsoftware.apiportal.universal.aspect.ValidateArgument;
import com.jmsoftware.common.bean.ResponseBodyBean;
import com.jmsoftware.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
import com.jmsoftware.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
import com.jmsoftware.common.domain.authcenter.role.GetRoleListByUserIdPayload;
import com.jmsoftware.common.domain.authcenter.role.GetRoleListByUserIdResponse;
import com.jmsoftware.common.domain.authcenter.user.GetUserByLoginTokenPayload;
Expand All @@ -11,6 +14,8 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.validation.Valid;

/**
* <h1>AuthCenterRemoteApi</h1>
* <p>
Expand All @@ -27,24 +32,37 @@ public interface AuthCenterRemoteApi {
* @param payload the payload
* @return the user by login token
*/
@ValidateArgument
@PostMapping("/user-remote-api/get-user-by-login-token")
ResponseBodyBean<GetUserByLoginTokenResponse> getUserByLoginToken(@RequestBody GetUserByLoginTokenPayload payload);
ResponseBodyBean<GetUserByLoginTokenResponse> getUserByLoginToken(@Valid @RequestBody GetUserByLoginTokenPayload payload);

/**
* Gets role list by user id.
*
* @param payload the payload
* @return the role list by user id
*/
@ValidateArgument
@PostMapping("/role-remote-api/get-role-list-by-user-id")
ResponseBodyBean<GetRoleListByUserIdResponse> getRoleListByUserId(@RequestBody GetRoleListByUserIdPayload payload);
ResponseBodyBean<GetRoleListByUserIdResponse> getRoleListByUserId(@Valid @RequestBody GetRoleListByUserIdPayload payload);

/**
* Save user for registering response body bean.
*
* @param payload the payload
* @return the response body bean
*/
@ValidateArgument
@PostMapping("/user-remote-api/save-user-for-registering")
ResponseBodyBean<SaveUserForRegisteringResponse> saveUserForRegistering(@RequestBody SaveUserForRegisteringPayload payload);
ResponseBodyBean<SaveUserForRegisteringResponse> saveUserForRegistering(@Valid @RequestBody SaveUserForRegisteringPayload payload);

/**
* Gets permission list by role id list.
*
* @param payload the payload
* @return the permission list by role id list
*/
@ValidateArgument
@PostMapping("/permission-remote-api/get-permission-list-by-role-id-list")
ResponseBodyBean<GetPermissionListByRoleIdListResponse> getPermissionListByRoleIdList(@Valid @RequestBody GetPermissionListByRoleIdListPayload payload);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import com.jmsoftware.common.constant.HttpStatus;
import com.jmsoftware.common.util.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;

/**
Expand All @@ -14,12 +16,24 @@
* @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
* @date 5/2/20 11:41 PM
**/
@Slf4j
@Configuration
public class SecurityHandlerConfiguration {
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return ((request, response, authException) -> {
log.error("Authentication encountered an exception! Exception message: {}", authException.getMessage(),
authException);
ResponseUtil.renderJson(response, HttpStatus.FORBIDDEN, null);
});
}

@Bean
public AccessDeniedHandler accessDeniedHandler() {
return (request, response, accessDeniedException) -> ResponseUtil.renderJson(response,
HttpStatus.FORBIDDEN,
null);
return ((request, response, accessDeniedException) -> {
log.error("Access was denied! Exception message: {}", accessDeniedException.getMessage(),
accessDeniedException);
ResponseUtil.renderJson(response, HttpStatus.FORBIDDEN, null);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

Expand All @@ -36,6 +37,7 @@
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CustomConfiguration customConfiguration;
private final AccessDeniedHandler accessDeniedHandler;
private final AuthenticationEntryPoint authenticationEntryPoint;
private final CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
private final JwtAuthenticationFilter jwtAuthenticationFilter;

Expand Down Expand Up @@ -83,7 +85,10 @@ protected void configure(HttpSecurity http) throws Exception {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)

// Exception handling
.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler);
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);

// Add customized JWT filter
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jmsoftware.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
import com.jmsoftware.common.domain.authcenter.user.GetUserByLoginTokenResponse;
import com.jmsoftware.common.domain.authcenter.user.UserStatus;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -94,7 +95,7 @@ public class UserPrincipal implements UserDetails {
* @return user principal
*/
public static UserPrincipal create(GetUserByLoginTokenResponse user, List<String> roleNameList,
List<PermissionPO> permissionList) {
List<GetPermissionListByRoleIdListResponse.Permission> permissionList) {
val authorities =
permissionList.stream()
.filter(permission -> StrUtil.isNotBlank(permission.getPermissionExpression()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,14 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
UserDetails userDetails;
try {
userDetails = customUserDetailsServiceImpl.loadUserByUsername(username);
} catch (UsernameNotFoundException e) {
log.error("Cannot find user by username: {}", username);
ResponseUtil.renderJson(response, HttpStatus.UNAUTHORIZED, null);
} catch (Exception e) {
log.error("Exception occurred when loading user by username! Exception message: {} Username: {}",
e.getMessage(), username);
if (e instanceof UsernameNotFoundException) {
ResponseUtil.renderJson(response, HttpStatus.UNAUTHORIZED, null);
return;
}
ResponseUtil.renderJson(response, HttpStatus.ERROR, e.getMessage());
return;
}
val authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.jmsoftware.apiportal.remoteapi.AuthCenterRemoteApi;
import com.jmsoftware.apiportal.universal.domain.PermissionPO;
import com.jmsoftware.apiportal.universal.domain.UserPrincipal;
import com.jmsoftware.apiportal.universal.mapper.PermissionMapper;
import com.jmsoftware.common.constant.HttpStatus;
import com.jmsoftware.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
import com.jmsoftware.common.domain.authcenter.role.GetRoleListByUserIdPayload;
import com.jmsoftware.common.domain.authcenter.role.GetRoleListByUserIdResponse;
import com.jmsoftware.common.domain.authcenter.user.GetUserByLoginTokenPayload;
Expand All @@ -19,7 +18,6 @@
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
Expand All @@ -33,7 +31,6 @@
@Service
@RequiredArgsConstructor
public class CustomUserDetailsServiceImpl implements UserDetailsService {
private final PermissionMapper permissionMapper;
private final AuthCenterRemoteApi authCenterRemoteApi;

@Override
Expand All @@ -54,12 +51,14 @@ public UserDetails loadUserByUsername(String credentials) throws UsernameNotFoun
if (CollUtil.isEmpty(roleList)) {
throw new SecurityException(HttpStatus.ROLE_NOT_FOUND);
}
List<Long> roleIdList = roleList.stream()
.map(GetRoleListByUserIdResponse.Role::getId)
.collect(Collectors.toList());
List<PermissionPO> permissionList = permissionMapper.selectByRoleIdList(roleIdList);
val payload2 = new GetPermissionListByRoleIdListPayload();
roleList.forEach(role -> {
payload2.getRoleIdList().add(role.getId());
});
val permissionListByRoleIdListResponse = authCenterRemoteApi.getPermissionListByRoleIdList(payload2);
val roleNameList =
roleList.stream().map(GetRoleListByUserIdResponse.Role::getName).collect(Collectors.toList());
return UserPrincipal.create(data, roleNameList, permissionList);
return UserPrincipal.create(data, roleNameList,
permissionListByRoleIdListResponse.getData().getPermissionList());
}
}
Loading

0 comments on commit d80b182

Please sign in to comment.