mirror of https://github.com/halo-dev/halo
Add security module
parent
c9c68eef54
commit
f7b90652ba
|
@ -3,6 +3,11 @@ package cc.ryanc.halo.config;
|
|||
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||
import cc.ryanc.halo.filter.CorsFilter;
|
||||
import cc.ryanc.halo.filter.LogFilter;
|
||||
import cc.ryanc.halo.security.filter.AdminAuthenticationFilter;
|
||||
import cc.ryanc.halo.security.filter.ApiAuthenticationFilter;
|
||||
import cc.ryanc.halo.security.handler.AdminAuthenticationFailureHandler;
|
||||
import cc.ryanc.halo.security.handler.DefaultAuthenticationFailureHandler;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -49,4 +54,30 @@ public class HaloConfiguration {
|
|||
|
||||
return logFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<ApiAuthenticationFilter> apiAuthenticationFilter(HaloProperties haloProperties, ObjectMapper objectMapper) {
|
||||
ApiAuthenticationFilter apiFilter = new ApiAuthenticationFilter();
|
||||
// Set failure handler
|
||||
apiFilter.setFailureHandler(new DefaultAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
|
||||
|
||||
FilterRegistrationBean<ApiAuthenticationFilter> authenticationFilter = new FilterRegistrationBean<>();
|
||||
authenticationFilter.setFilter(apiFilter);
|
||||
authenticationFilter.addUrlPatterns("/api/*");
|
||||
authenticationFilter.setOrder(0);
|
||||
return authenticationFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<AdminAuthenticationFilter> adminAuthenticationFilter(HaloProperties haloProperties, ObjectMapper objectMapper) {
|
||||
AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter();
|
||||
// Set failure handler
|
||||
adminFilter.setFailureHandler(new AdminAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
|
||||
|
||||
FilterRegistrationBean<AdminAuthenticationFilter> authenticationFilter = new FilterRegistrationBean<>();
|
||||
authenticationFilter.setFilter(adminFilter);
|
||||
authenticationFilter.addUrlPatterns("/admin/*");
|
||||
authenticationFilter.setOrder(1);
|
||||
return authenticationFilter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
package cc.ryanc.halo.config;
|
||||
|
||||
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||
import cc.ryanc.halo.security.resolver.AuthenticationArgumentResolver;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
|
@ -32,53 +34,13 @@ import java.util.Locale;
|
|||
@PropertySource(value = "classpath:application.yaml", ignoreResourceNotFound = true, encoding = "UTF-8")
|
||||
public class WebMvcAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
// @Autowired
|
||||
// private LoginInterceptor loginInterceptor;
|
||||
//
|
||||
// @Autowired
|
||||
// private InstallInterceptor installInterceptor;
|
||||
//
|
||||
// @Autowired
|
||||
// private ApiInterceptor apiInterceptor;
|
||||
//
|
||||
// @Autowired
|
||||
// private LocaleInterceptor localeInterceptor;
|
||||
//
|
||||
@Autowired
|
||||
private HaloProperties haloProperties;
|
||||
//
|
||||
// /**
|
||||
// * 注册拦截器
|
||||
// *
|
||||
// * @param registry registry
|
||||
// */
|
||||
// @Override
|
||||
// public void addInterceptors(InterceptorRegistry registry) {
|
||||
// registry.addInterceptor(loginInterceptor)
|
||||
// .addPathPatterns("/admin.*")
|
||||
// .addPathPatterns("/admin/**")
|
||||
// .addPathPatterns("/backup/**")
|
||||
// .excludePathPatterns("/admin/login")
|
||||
// .excludePathPatterns("/admin/getLogin")
|
||||
// .excludePathPatterns("/admin/findPassword")
|
||||
// .excludePathPatterns("/admin/sendResetPasswordEmail")
|
||||
// .excludePathPatterns("/admin/toResetPassword")
|
||||
// .excludePathPatterns("/admin/resetPassword")
|
||||
// .excludePathPatterns("/static/**");
|
||||
// registry.addInterceptor(installInterceptor)
|
||||
// .addPathPatterns("/**")
|
||||
// .excludePathPatterns("/install")
|
||||
// .excludePathPatterns("/install/do")
|
||||
// .excludePathPatterns("/static/**");
|
||||
// registry.addInterceptor(apiInterceptor)
|
||||
// .addPathPatterns("/api/**");
|
||||
// registry.addInterceptor(localeInterceptor)
|
||||
// .addPathPatterns("/admin.*")
|
||||
// .addPathPatterns("/admin/**")
|
||||
// .addPathPatterns("/install");
|
||||
// registry.addInterceptor(localeChangeInterceptor())
|
||||
// .addPathPatterns("/install");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
resolvers.add(new AuthenticationArgumentResolver());
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置静态资源路径
|
||||
|
|
|
@ -16,4 +16,9 @@ public class HaloProperties {
|
|||
* Doc api disabled. (Default is true)
|
||||
*/
|
||||
private Boolean docDisabled = true;
|
||||
|
||||
/**
|
||||
* Production env. (Default is true)
|
||||
*/
|
||||
private Boolean productionEnv = true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package cc.ryanc.halo.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Authentication exception.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public class AuthenticationException extends HaloException {
|
||||
|
||||
public AuthenticationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AuthenticationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() {
|
||||
return HttpStatus.UNAUTHORIZED;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
|||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Page with title only dto.
|
||||
* Post minimal output dto.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package cc.ryanc.halo.model.support;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* Global response entity.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ErrorResponse {
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String message;
|
||||
|
||||
private String devMessage;
|
||||
|
||||
private Object data;
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cc.ryanc.halo.security.authentication;
|
||||
|
||||
import cc.ryanc.halo.security.support.UserDetail;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* Authentication.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface Authentication {
|
||||
|
||||
/**
|
||||
* Get user detail.
|
||||
*
|
||||
* @return user detail
|
||||
*/
|
||||
@NonNull
|
||||
UserDetail getDetail();
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cc.ryanc.halo.security.authentication;
|
||||
|
||||
import cc.ryanc.halo.security.support.UserDetail;
|
||||
|
||||
/**
|
||||
* Authentication implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public class AuthenticationImpl implements Authentication {
|
||||
|
||||
private final UserDetail userDetail;
|
||||
|
||||
public AuthenticationImpl(UserDetail userDetail) {
|
||||
this.userDetail = userDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetail getDetail() {
|
||||
return userDetail;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package cc.ryanc.halo.security.context;
|
||||
|
||||
import cc.ryanc.halo.security.authentication.Authentication;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Security context interface.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface SecurityContext {
|
||||
|
||||
/**
|
||||
* Gets the currently authenticated principal.
|
||||
*
|
||||
* @return the Authentication or null if authentication information is unavailable
|
||||
*/
|
||||
@Nullable
|
||||
Authentication getAuthentication();
|
||||
|
||||
/**
|
||||
* Changes the currently authenticated principal, or removes the authentication information.
|
||||
*
|
||||
* @param authentication the new authentication or null if no further authentication should not be stored
|
||||
*/
|
||||
void setAuthentication(@Nullable Authentication authentication);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cc.ryanc.halo.security.context;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Security context holder.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 12/11/18
|
||||
*/
|
||||
public class SecurityContextHolder {
|
||||
|
||||
private final static ThreadLocal<SecurityContext> CONTEXT_HOLDER = new ThreadLocal<>();
|
||||
|
||||
private SecurityContextHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets context.
|
||||
*
|
||||
* @return security context
|
||||
*/
|
||||
@NonNull
|
||||
public static SecurityContext getContext() {
|
||||
// Get from thread local
|
||||
SecurityContext context = CONTEXT_HOLDER.get();
|
||||
if (context == null) {
|
||||
// If no context is available now then create an empty context
|
||||
context = createEmptyContext();
|
||||
// Set to thread local
|
||||
CONTEXT_HOLDER.set(context);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets security context.
|
||||
*
|
||||
* @param context security context
|
||||
*/
|
||||
public static void setContext(@Nullable SecurityContext context) {
|
||||
CONTEXT_HOLDER.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears context.
|
||||
*/
|
||||
public static void clearContext() {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty security context.
|
||||
*
|
||||
* @return an empty security context
|
||||
*/
|
||||
@NonNull
|
||||
private static SecurityContext createEmptyContext() {
|
||||
return new SecurityContextImpl();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package cc.ryanc.halo.security.context;
|
||||
|
||||
import cc.ryanc.halo.security.authentication.Authentication;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Security context implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SecurityContextImpl implements SecurityContext {
|
||||
|
||||
private Authentication authentication;
|
||||
|
||||
@Override
|
||||
public Authentication getAuthentication() {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthentication(Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cc.ryanc.halo.security.filter;
|
||||
|
||||
import cc.ryanc.halo.security.handler.AuthenticationFailureHandler;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Admin authentication filter.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public class AdminAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private AuthenticationFailureHandler failureHandler;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
// TODO Handle admin authentication
|
||||
}
|
||||
|
||||
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
this.failureHandler = failureHandler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package cc.ryanc.halo.security.filter;
|
||||
|
||||
import cc.ryanc.halo.security.handler.AuthenticationFailureHandler;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Api authentication Filter
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public class ApiAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private AuthenticationFailureHandler failureHandler;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
// TODO Handle authentication
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
this.failureHandler = failureHandler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
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;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Authentication failure handler.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
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.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package cc.ryanc.halo.security.handler;
|
||||
|
||||
import cc.ryanc.halo.exception.HaloException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Authentication failure handler.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface AuthenticationFailureHandler {
|
||||
|
||||
/**
|
||||
* Calls when a user has been unsuccessfully authenticated.
|
||||
*
|
||||
* @param request http servlet request
|
||||
* @param response http servlet response
|
||||
* @param exception api exception
|
||||
* @throws IOException io exception
|
||||
* @throws ServletException service exception
|
||||
*/
|
||||
void onFailure(HttpServletRequest request, HttpServletResponse response, HaloException exception) throws IOException, ServletException;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package cc.ryanc.halo.security.handler;
|
||||
|
||||
import cc.ryanc.halo.exception.HaloException;
|
||||
import cc.ryanc.halo.model.support.ErrorResponse;
|
||||
import cc.ryanc.halo.utils.ExceptionUtils;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Default AuthenticationFailureHandler.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 12/12/18
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
private final boolean productionEnv;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public DefaultAuthenticationFailureHandler(boolean productionEnv,
|
||||
ObjectMapper objectMapper) {
|
||||
this.productionEnv = productionEnv;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(HttpServletRequest request, HttpServletResponse response, HaloException exception) throws IOException, ServletException {
|
||||
log.warn("Handle unsuccessful authentication, ip: [{}]", ServletUtil.getClientIP(request));
|
||||
|
||||
ErrorResponse errorDetail = new ErrorResponse();
|
||||
|
||||
errorDetail.setMessage(exception.getMessage());
|
||||
|
||||
if (!productionEnv) {
|
||||
errorDetail.setDevMessage(ExceptionUtils.getStackTrace(exception));
|
||||
}
|
||||
|
||||
log.debug("Response error: [{}]", errorDetail);
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
response.setStatus(exception.getStatus().value());
|
||||
response.getWriter().write(objectMapper.writeValueAsString(errorDetail));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package cc.ryanc.halo.security.resolver;
|
||||
|
||||
import cc.ryanc.halo.exception.AuthenticationException;
|
||||
import cc.ryanc.halo.model.entity.User;
|
||||
import cc.ryanc.halo.security.authentication.Authentication;
|
||||
import cc.ryanc.halo.security.context.SecurityContextHolder;
|
||||
import cc.ryanc.halo.security.support.UserDetail;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Authentication argument resolver.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 12/11/18
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthenticationArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
public AuthenticationArgumentResolver() {
|
||||
log.debug("Initializing AuthenticationArgumentResolver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Class<?> parameterType = parameter.getParameterType();
|
||||
return (Authentication.class.isAssignableFrom(parameterType) ||
|
||||
UserDetail.class.isAssignableFrom(parameterType) ||
|
||||
User.class.isAssignableFrom(parameterType));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
|
||||
log.debug("Handle AuthenticationArgument");
|
||||
|
||||
Class<?> parameterType = parameter.getParameterType();
|
||||
|
||||
Authentication authentication = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
|
||||
.orElseThrow(() -> new AuthenticationException("You haven't signed in yet"));
|
||||
|
||||
if (Authentication.class.isAssignableFrom(parameterType)) {
|
||||
return authentication;
|
||||
} else if (UserDetail.class.isAssignableFrom(parameterType)) {
|
||||
return authentication.getDetail();
|
||||
} else if (User.class.isAssignableFrom(parameterType)) {
|
||||
return authentication.getDetail().getUser();
|
||||
}
|
||||
|
||||
// Should never happen...
|
||||
throw new UnsupportedOperationException("Unknown parameter type: " + parameterType);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package cc.ryanc.halo.security.support;
|
||||
|
||||
import cc.ryanc.halo.exception.AuthenticationException;
|
||||
import cc.ryanc.halo.model.entity.User;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* User detail.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
public class UserDetail {
|
||||
|
||||
private User user;
|
||||
|
||||
/**
|
||||
* Gets user info.
|
||||
*
|
||||
* @return user info
|
||||
* @throws AuthenticationException throws if the user is null
|
||||
*/
|
||||
@NonNull
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import org.springframework.data.domain.Page;
|
|||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
|
@ -40,12 +41,12 @@ public class PostController {
|
|||
* @param status post status
|
||||
* @param page current page
|
||||
* @param sort sort
|
||||
*
|
||||
* @return template path: admin/admin_post.ftl
|
||||
*/
|
||||
@GetMapping
|
||||
public String posts(Model model,
|
||||
@RequestParam(value = "status", defaultValue = "0") PostStatus status,
|
||||
@RequestParam(value = "status", defaultValue = "PUBLISHED") PostStatus status,
|
||||
@PageableDefault Pageable defaultPageable,
|
||||
@RequestParam(value = "page", defaultValue = "0") Integer page,
|
||||
@SortDefault.SortDefaults({
|
||||
@SortDefault(sort = "postPriority", direction = DESC),
|
||||
|
|
Loading…
Reference in New Issue