Refactor AdminAuthenticationFilter

pull/137/head
johnniang 2019-03-29 12:15:26 +08:00
parent e973bf2200
commit 523afaebe4
6 changed files with 105 additions and 39 deletions

View File

@ -69,7 +69,9 @@ public class HaloConfiguration {
public FilterRegistrationBean<ApiAuthenticationFilter> apiAuthenticationFilter(HaloProperties haloProperties, ObjectMapper objectMapper) {
ApiAuthenticationFilter apiFilter = new ApiAuthenticationFilter();
// Set failure handler
apiFilter.setFailureHandler(new DefaultAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
apiFilter.setFailureHandler(new DefaultAuthenticationFailureHandler()
.setProductionEnv(haloProperties.getProductionEnv())
.setObjectMapper(objectMapper));
FilterRegistrationBean<ApiAuthenticationFilter> authenticationFilter = new FilterRegistrationBean<>();
authenticationFilter.setFilter(apiFilter);
@ -79,19 +81,19 @@ public class HaloConfiguration {
}
@Bean
public FilterRegistrationBean<AdminAuthenticationFilter> adminAuthenticationFilter(HaloProperties haloProperties,
ObjectMapper objectMapper,
StringCacheStore cacheStore,
UserService userService) {
AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter(cacheStore, userService, "/admin/api/login");
// Set auth enabled
adminFilter.setAuthEnabled(haloProperties.getAuthEnabled());
// Set failure handler
adminFilter.setFailureHandler(new AdminAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
public FilterRegistrationBean<AdminAuthenticationFilter> adminAuthenticationFilter(StringCacheStore cacheStore,
UserService userService,
HaloProperties haloProperties,
ObjectMapper objectMapper) {
AdminAuthenticationFilter adminAuthenticationFilter = new AdminAuthenticationFilter(cacheStore, userService, haloProperties);
// Config the admin filter
adminAuthenticationFilter.setExcludeUrlPatterns("/admin/api/login")
.setFailureHandler(new AdminAuthenticationFailureHandler()
.setProductionEnv(haloProperties.getProductionEnv())
.setObjectMapper(objectMapper));
FilterRegistrationBean<AdminAuthenticationFilter> authenticationFilter = new FilterRegistrationBean<>();
authenticationFilter.setFilter(adminFilter);
authenticationFilter.setFilter(adminAuthenticationFilter);
authenticationFilter.addUrlPatterns("/admin/*");
authenticationFilter.setOrder(1);
return authenticationFilter;

View File

@ -1,12 +1,14 @@
package cc.ryanc.halo.security.filter;
import cc.ryanc.halo.cache.StringCacheStore;
import cc.ryanc.halo.config.properties.HaloProperties;
import cc.ryanc.halo.exception.AuthenticationException;
import cc.ryanc.halo.model.entity.User;
import cc.ryanc.halo.security.authentication.AuthenticationImpl;
import cc.ryanc.halo.security.context.SecurityContextHolder;
import cc.ryanc.halo.security.context.SecurityContextImpl;
import cc.ryanc.halo.security.handler.AuthenticationFailureHandler;
import cc.ryanc.halo.security.handler.DefaultAuthenticationFailureHandler;
import cc.ryanc.halo.security.support.UserDetail;
import cc.ryanc.halo.service.UserService;
import cc.ryanc.halo.utils.JsonUtils;
@ -49,30 +51,29 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
private AuthenticationFailureHandler failureHandler;
/**
* Authentication enabled.
*/
private boolean authEnabled = true;
private final HaloProperties haloProperties;
private final StringCacheStore cacheStore;
private final UserService userService;
private final Collection<String> excludeUrlPatterns;
private final AntPathMatcher antPathMatcher;
public AdminAuthenticationFilter(StringCacheStore cacheStore, UserService userService, String... excludeUrls) {
private Collection<String> excludeUrlPatterns;
public AdminAuthenticationFilter(StringCacheStore cacheStore,
UserService userService,
HaloProperties haloProperties) {
this.cacheStore = cacheStore;
this.userService = userService;
this.excludeUrlPatterns = excludeUrls == null ? Collections.emptyList() : Collections.unmodifiableCollection(Arrays.asList(excludeUrls));
this.haloProperties = haloProperties;
antPathMatcher = new AntPathMatcher();
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (!authEnabled) {
if (!haloProperties.getAuthEnabled()) {
List<User> users = userService.listAll();
if (!users.isEmpty()) {
// Set security context
@ -93,7 +94,7 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
Optional<String> userDetailOptional = cacheStore.get(token);
if (!userDetailOptional.isPresent()) {
failureHandler.onFailure(request, response, new AuthenticationException("The token has been expired or not exist").setErrorData(token));
getFailureHandler().onFailure(request, response, new AuthenticationException("The token has been expired or not exist").setErrorData(token));
return;
}
@ -120,7 +121,7 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
return;
}
failureHandler.onFailure(request, response, new AuthenticationException("You have to login before accessing admin api"));
getFailureHandler().onFailure(request, response, new AuthenticationException("You have to login before accessing admin api"));
}
@Override
@ -128,12 +129,39 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
return excludeUrlPatterns.stream().anyMatch(p -> antPathMatcher.match(p, request.getServletPath()));
}
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
this.failureHandler = failureHandler;
/**
* Gets authentication failure handler. (Default: @DefaultAuthenticationFailureHandler)
*
* @return authentication failure handler
*/
public AuthenticationFailureHandler getFailureHandler() {
if (failureHandler == null) {
synchronized (this) {
// Create default authentication failure handler
failureHandler = new DefaultAuthenticationFailureHandler().setProductionEnv(haloProperties.getProductionEnv());
}
}
return failureHandler;
}
public void setAuthEnabled(boolean authEnabled) {
this.authEnabled = authEnabled;
/**
* Sets authentication failure handler.
*
* @param failureHandler authentication failure handler
*/
public AdminAuthenticationFilter setFailureHandler(AuthenticationFailureHandler failureHandler) {
this.failureHandler = failureHandler;
return this;
}
/**
* Set exclude url patterns.
*
* @param excludeUrls exclude urls
*/
public AdminAuthenticationFilter setExcludeUrlPatterns(String... excludeUrls) {
this.excludeUrlPatterns = excludeUrls == null ? Collections.emptyList() : Collections.unmodifiableCollection(Arrays.asList(excludeUrls));
return this;
}
/**

View File

@ -1,7 +1,6 @@
package cc.ryanc.halo.security.handler;
import cc.ryanc.halo.exception.HaloException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -15,10 +14,6 @@ import java.io.IOException;
*/
public class AdminAuthenticationFailureHandler extends DefaultAuthenticationFailureHandler {
public AdminAuthenticationFailureHandler(boolean productionEnv, ObjectMapper objectMapper) {
super(productionEnv, objectMapper);
}
@Override
public void onFailure(HttpServletRequest request, HttpServletResponse response, HaloException exception) throws IOException, ServletException {
// TODO handler the admin authentication failure.

View File

@ -3,10 +3,12 @@ package cc.ryanc.halo.security.handler;
import cc.ryanc.halo.exception.HaloException;
import cc.ryanc.halo.model.support.BaseResponse;
import cc.ryanc.halo.utils.ExceptionUtils;
import cc.ryanc.halo.utils.JsonUtils;
import cn.hutool.extra.servlet.ServletUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -22,14 +24,11 @@ import java.io.IOException;
@Slf4j
public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final boolean productionEnv;
private boolean productionEnv = true;
private final ObjectMapper objectMapper;
private ObjectMapper objectMapper = JsonUtils.DEFAULT_JSON_MAPPER;
public DefaultAuthenticationFailureHandler(boolean productionEnv,
ObjectMapper objectMapper) {
this.productionEnv = productionEnv;
this.objectMapper = objectMapper;
public DefaultAuthenticationFailureHandler() {
}
@Override
@ -52,4 +51,21 @@ public class DefaultAuthenticationFailureHandler implements AuthenticationFailur
response.getWriter().write(objectMapper.writeValueAsString(errorDetail));
}
/**
* Sets custom object mapper.
*
* @param objectMapper object mapper
* @return current authentication failure handler
*/
public DefaultAuthenticationFailureHandler setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "Object mapper must not be null");
this.objectMapper = objectMapper;
return this;
}
public DefaultAuthenticationFailureHandler setProductionEnv(boolean productionEnv) {
this.productionEnv = productionEnv;
return this;
}
}

View File

@ -11,6 +11,8 @@ import cc.ryanc.halo.model.vo.CommentListVO;
import cc.ryanc.halo.model.vo.CommentVO;
import cc.ryanc.halo.repository.CommentRepository;
import cc.ryanc.halo.repository.PostRepository;
import cc.ryanc.halo.security.authentication.Authentication;
import cc.ryanc.halo.security.context.SecurityContextHolder;
import cc.ryanc.halo.service.CommentService;
import cc.ryanc.halo.service.OptionService;
import cc.ryanc.halo.service.base.AbstractCrudService;
@ -110,7 +112,12 @@ public class CommentServiceImpl extends AbstractCrudService<Comment, Long> imple
comment.setIpAddress(ServletUtil.getClientIP(request));
comment.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, HttpHeaders.USER_AGENT));
// TODO Check user login status and set this field
comment.setIsAdmin(false);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
// If the user is login
comment.setIsAdmin(true);
}
comment.setAuthor(HtmlUtils.htmlEscape(comment.getAuthor()));
comment.setGavatarMd5(SecureUtil.md5(comment.getEmail()));

View File

@ -2,12 +2,17 @@ package cc.ryanc.halo.web.controller.admin.api;
import cc.ryanc.halo.model.dto.CommentOutputDTO;
import cc.ryanc.halo.model.entity.Comment;
import cc.ryanc.halo.model.entity.User;
import cc.ryanc.halo.model.enums.BlogProperties;
import cc.ryanc.halo.model.enums.CommentStatus;
import cc.ryanc.halo.model.params.CommentParam;
import cc.ryanc.halo.model.vo.CommentListVO;
import cc.ryanc.halo.security.authentication.Authentication;
import cc.ryanc.halo.security.context.SecurityContextHolder;
import cc.ryanc.halo.service.CommentService;
import cc.ryanc.halo.service.OptionService;
import cc.ryanc.halo.service.PostService;
import cc.ryanc.halo.utils.ValidationUtils;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@ -58,6 +63,19 @@ public class CommentController {
@PostMapping
public CommentOutputDTO createBy(@Valid @RequestBody CommentParam commentParam, HttpServletRequest request) {
// Get authentication
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
User user = authentication.getDetail().getUser();
// If the admin is login
commentParam.setAuthor(user.getNickname());
commentParam.setEmail(user.getEmail());
commentParam.setAuthor(optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL));
}
// Validate the comment param manually
ValidationUtils.validate(commentParam);
// Check post id
postService.mustExistById(commentParam.getPostId());