From dd2caca58d0f1066a9e72c386ba5839444de8081 Mon Sep 17 00:00:00 2001 From: johnniang Date: Thu, 28 Mar 2019 01:16:15 +0800 Subject: [PATCH] Complete admin login api --- .../ryanc/halo/config/HaloConfiguration.java | 2 +- .../ryanc/halo/model/dto/UserOutputDTO.java | 2 -- .../ryanc/halo/model/params/LoginParam.java | 27 ++++++++++++++++ .../filter/AdminAuthenticationFilter.java | 18 ++++++++++- .../halo/security/support/UserDetail.java | 4 +++ .../cc/ryanc/halo/service/UserService.java | 8 +++-- .../halo/service/impl/UserServiceImpl.java | 9 ++++-- .../controller/admin/api/AdminController.java | 31 +++++++++++++------ .../java/cc/ryanc/halo/utils/BcryptTest.java | 19 ++++++++++++ 9 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 src/main/java/cc/ryanc/halo/model/params/LoginParam.java create mode 100644 src/test/java/cc/ryanc/halo/utils/BcryptTest.java diff --git a/src/main/java/cc/ryanc/halo/config/HaloConfiguration.java b/src/main/java/cc/ryanc/halo/config/HaloConfiguration.java index 6a1b649db..6b5c96f76 100644 --- a/src/main/java/cc/ryanc/halo/config/HaloConfiguration.java +++ b/src/main/java/cc/ryanc/halo/config/HaloConfiguration.java @@ -81,7 +81,7 @@ public class HaloConfiguration { public FilterRegistrationBean adminAuthenticationFilter(HaloProperties haloProperties, ObjectMapper objectMapper, StringCacheStore cacheStore) { - AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter(cacheStore); + AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter(cacheStore, "/admin/api/login"); // Set failure handler adminFilter.setFailureHandler(new AdminAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper)); diff --git a/src/main/java/cc/ryanc/halo/model/dto/UserOutputDTO.java b/src/main/java/cc/ryanc/halo/model/dto/UserOutputDTO.java index 2182ffdaf..e46613d26 100644 --- a/src/main/java/cc/ryanc/halo/model/dto/UserOutputDTO.java +++ b/src/main/java/cc/ryanc/halo/model/dto/UserOutputDTO.java @@ -31,8 +31,6 @@ public class UserOutputDTO implements OutputConverter { private String description; - private Date expireTime; - private Date createTime; private Date updateTime; diff --git a/src/main/java/cc/ryanc/halo/model/params/LoginParam.java b/src/main/java/cc/ryanc/halo/model/params/LoginParam.java new file mode 100644 index 000000000..cd8c4e63d --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/params/LoginParam.java @@ -0,0 +1,27 @@ +package cc.ryanc.halo.model.params; + +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * Login param. + * + * @author johnniang + * @date 3/28/19 + */ +@Data +@ToString +public class LoginParam { + + @NotBlank(message = "Username or email must not be blank") + @Size(max = 255, message = "Length of username or email must not be more than {max}") + private String username; + + @NotBlank(message = "Password must not be blank") + @Size(max = 100, message = "Length of password must not be more than {max}") + private String password; + +} diff --git a/src/main/java/cc/ryanc/halo/security/filter/AdminAuthenticationFilter.java b/src/main/java/cc/ryanc/halo/security/filter/AdminAuthenticationFilter.java index a28bacc97..2f7655392 100644 --- a/src/main/java/cc/ryanc/halo/security/filter/AdminAuthenticationFilter.java +++ b/src/main/java/cc/ryanc/halo/security/filter/AdminAuthenticationFilter.java @@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; +import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.web.filter.OncePerRequestFilter; @@ -20,6 +21,9 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Optional; /** @@ -48,8 +52,14 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter { private final StringCacheStore cacheStore; - public AdminAuthenticationFilter(StringCacheStore cacheStore) { + private final Collection excludeUrlPatterns; + + private final AntPathMatcher antPathMatcher; + + public AdminAuthenticationFilter(StringCacheStore cacheStore, String... excludeUrls) { this.cacheStore = cacheStore; + this.excludeUrlPatterns = excludeUrls == null ? Collections.emptyList() : Collections.unmodifiableCollection(Arrays.asList(excludeUrls)); + antPathMatcher = new AntPathMatcher(); } @Override @@ -93,6 +103,11 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter { failureHandler.onFailure(request, response, new AuthenticationException("You have to login before accessing admin api")); } + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + return excludeUrlPatterns.stream().anyMatch(p -> antPathMatcher.match(p, request.getServletPath())); + } + public void setFailureHandler(AuthenticationFailureHandler failureHandler) { this.failureHandler = failureHandler; } @@ -117,4 +132,5 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter { return token; } + } diff --git a/src/main/java/cc/ryanc/halo/security/support/UserDetail.java b/src/main/java/cc/ryanc/halo/security/support/UserDetail.java index df455a1c1..abd1bc377 100644 --- a/src/main/java/cc/ryanc/halo/security/support/UserDetail.java +++ b/src/main/java/cc/ryanc/halo/security/support/UserDetail.java @@ -2,7 +2,9 @@ package cc.ryanc.halo.security.support; import cc.ryanc.halo.exception.AuthenticationException; import cc.ryanc.halo.model.entity.User; +import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.ToString; import org.springframework.lang.NonNull; @@ -13,6 +15,8 @@ import org.springframework.lang.NonNull; */ @ToString @EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor public class UserDetail { private User user; diff --git a/src/main/java/cc/ryanc/halo/service/UserService.java b/src/main/java/cc/ryanc/halo/service/UserService.java index 8f296c80a..526ba783e 100755 --- a/src/main/java/cc/ryanc/halo/service/UserService.java +++ b/src/main/java/cc/ryanc/halo/service/UserService.java @@ -6,6 +6,7 @@ import cc.ryanc.halo.model.params.UserParam; import cc.ryanc.halo.service.base.CrudService; import org.springframework.lang.NonNull; +import javax.servlet.http.HttpSession; import java.util.Optional; /** @@ -68,12 +69,13 @@ public interface UserService extends CrudService { /** * Logins by username and password. * - * @param key username or email must not be blank - * @param password password must not be blank + * @param key username or email must not be blank + * @param password password must not be blank + * @param httpSession http session must not be null * @return user info */ @NonNull - User login(@NonNull String key, @NonNull String password); + User login(@NonNull String key, @NonNull String password, @NonNull HttpSession httpSession); /** * Updates user password. diff --git a/src/main/java/cc/ryanc/halo/service/impl/UserServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/UserServiceImpl.java index 778fbc057..b41f43c15 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/UserServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/UserServiceImpl.java @@ -6,6 +6,8 @@ import cc.ryanc.halo.exception.NotFoundException; import cc.ryanc.halo.model.entity.User; import cc.ryanc.halo.model.params.UserParam; import cc.ryanc.halo.repository.UserRepository; +import cc.ryanc.halo.security.filter.AdminAuthenticationFilter; +import cc.ryanc.halo.security.support.UserDetail; import cc.ryanc.halo.service.UserService; import cc.ryanc.halo.service.base.AbstractCrudService; import cc.ryanc.halo.utils.DateUtils; @@ -15,6 +17,7 @@ import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; import org.springframework.util.Assert; +import javax.servlet.http.HttpSession; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -72,9 +75,10 @@ public class UserServiceImpl extends AbstractCrudService implemen } @Override - public User login(String key, String password) { + public User login(String key, String password, HttpSession httpSession) { Assert.hasText(key, "Username or email must not be blank"); Assert.hasText(password, "Password must not be blank"); + Assert.notNull(httpSession, "Http session must not be null"); // Ger user by username User user = Validator.isEmail(key) ? getByEmailOfNonNull(key) : getByUsernameOfNonNull(key); @@ -105,7 +109,8 @@ public class UserServiceImpl extends AbstractCrudService implemen throw new BadRequestException("账号或者密码错误,您还有" + (MAX_LOGIN_TRY - loginFailureCount) + "次机会"); } - // TODO Set session or cache token + // Set session + httpSession.setAttribute(AdminAuthenticationFilter.ADMIN_SESSION_KEY, new UserDetail(user)); return user; } diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/api/AdminController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/api/AdminController.java index af2aa21b8..96084a860 100644 --- a/src/main/java/cc/ryanc/halo/web/controller/admin/api/AdminController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/api/AdminController.java @@ -1,17 +1,17 @@ package cc.ryanc.halo.web.controller.admin.api; import cc.ryanc.halo.model.dto.CountOutputDTO; +import cc.ryanc.halo.model.dto.UserOutputDTO; import cc.ryanc.halo.model.enums.BlogProperties; import cc.ryanc.halo.model.enums.PostStatus; -import cc.ryanc.halo.model.enums.PostType; -import cc.ryanc.halo.service.AttachmentService; -import cc.ryanc.halo.service.CommentService; -import cc.ryanc.halo.service.OptionService; -import cc.ryanc.halo.service.PostService; +import cc.ryanc.halo.model.params.LoginParam; +import cc.ryanc.halo.service.*; import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import javax.validation.Valid; /** * Admin controller. @@ -31,11 +31,18 @@ public class AdminController { private final OptionService optionService; - public AdminController(PostService postService, AttachmentService attachmentService, CommentService commentService, OptionService optionService) { + private final UserService userService; + + public AdminController(PostService postService, + AttachmentService attachmentService, + CommentService commentService, + OptionService optionService, + UserService userService) { this.postService = postService; this.attachmentService = attachmentService; this.commentService = commentService; this.optionService = optionService; + this.userService = userService; } @GetMapping("counts") @@ -48,4 +55,10 @@ public class AdminController { countOutputDTO.setEstablishDays(Long.valueOf(optionService.getByProperty(BlogProperties.WIDGET_DAYCOUNT).orElse("0"))); return countOutputDTO; } + + @PostMapping("login") + @ApiOperation("Logins with session") + public UserOutputDTO login(@Valid @RequestBody LoginParam loginParam, HttpServletRequest request) { + return new UserOutputDTO().convertFrom(userService.login(loginParam.getUsername(), loginParam.getPassword(), request.getSession())); + } } diff --git a/src/test/java/cc/ryanc/halo/utils/BcryptTest.java b/src/test/java/cc/ryanc/halo/utils/BcryptTest.java new file mode 100644 index 000000000..b11954ccf --- /dev/null +++ b/src/test/java/cc/ryanc/halo/utils/BcryptTest.java @@ -0,0 +1,19 @@ +package cc.ryanc.halo.utils; + +import cn.hutool.crypto.digest.BCrypt; +import org.junit.Test; + +/** + * BCrypt test. + * + * @author johnniang + * @date 3/28/19 + */ +public class BcryptTest { + + @Test + public void cryptTest() { + String cryptPassword = BCrypt.hashpw("opentest", BCrypt.gensalt()); + System.out.println("Crypt password: " + cryptPassword); + } +}