mirror of https://github.com/halo-dev/halo
Complete admin login api
parent
42032e3b78
commit
dd2caca58d
|
@ -81,7 +81,7 @@ public class HaloConfiguration {
|
||||||
public FilterRegistrationBean<AdminAuthenticationFilter> adminAuthenticationFilter(HaloProperties haloProperties,
|
public FilterRegistrationBean<AdminAuthenticationFilter> adminAuthenticationFilter(HaloProperties haloProperties,
|
||||||
ObjectMapper objectMapper,
|
ObjectMapper objectMapper,
|
||||||
StringCacheStore cacheStore) {
|
StringCacheStore cacheStore) {
|
||||||
AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter(cacheStore);
|
AdminAuthenticationFilter adminFilter = new AdminAuthenticationFilter(cacheStore, "/admin/api/login");
|
||||||
// Set failure handler
|
// Set failure handler
|
||||||
adminFilter.setFailureHandler(new AdminAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
|
adminFilter.setFailureHandler(new AdminAuthenticationFailureHandler(haloProperties.getProductionEnv(), objectMapper));
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,6 @@ public class UserOutputDTO implements OutputConverter<UserOutputDTO, User> {
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Date expireTime;
|
|
||||||
|
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
@ -20,6 +21,9 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,8 +52,14 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final StringCacheStore cacheStore;
|
private final StringCacheStore cacheStore;
|
||||||
|
|
||||||
public AdminAuthenticationFilter(StringCacheStore cacheStore) {
|
private final Collection<String> excludeUrlPatterns;
|
||||||
|
|
||||||
|
private final AntPathMatcher antPathMatcher;
|
||||||
|
|
||||||
|
public AdminAuthenticationFilter(StringCacheStore cacheStore, String... excludeUrls) {
|
||||||
this.cacheStore = cacheStore;
|
this.cacheStore = cacheStore;
|
||||||
|
this.excludeUrlPatterns = excludeUrls == null ? Collections.emptyList() : Collections.unmodifiableCollection(Arrays.asList(excludeUrls));
|
||||||
|
antPathMatcher = new AntPathMatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,6 +103,11 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
|
||||||
failureHandler.onFailure(request, response, new AuthenticationException("You have to login before accessing admin api"));
|
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) {
|
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||||
this.failureHandler = failureHandler;
|
this.failureHandler = failureHandler;
|
||||||
}
|
}
|
||||||
|
@ -117,4 +132,5 @@ public class AdminAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ package cc.ryanc.halo.security.support;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.AuthenticationException;
|
import cc.ryanc.halo.exception.AuthenticationException;
|
||||||
import cc.ryanc.halo.model.entity.User;
|
import cc.ryanc.halo.model.entity.User;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
@ -13,6 +15,8 @@ import org.springframework.lang.NonNull;
|
||||||
*/
|
*/
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class UserDetail {
|
public class UserDetail {
|
||||||
|
|
||||||
private User user;
|
private User user;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import cc.ryanc.halo.model.params.UserParam;
|
||||||
import cc.ryanc.halo.service.base.CrudService;
|
import cc.ryanc.halo.service.base.CrudService;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,10 +71,11 @@ public interface UserService extends CrudService<User, Integer> {
|
||||||
*
|
*
|
||||||
* @param key username or email must not be blank
|
* @param key username or email must not be blank
|
||||||
* @param password password must not be blank
|
* @param password password must not be blank
|
||||||
|
* @param httpSession http session must not be null
|
||||||
* @return user info
|
* @return user info
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
User login(@NonNull String key, @NonNull String password);
|
User login(@NonNull String key, @NonNull String password, @NonNull HttpSession httpSession);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates user password.
|
* Updates user password.
|
||||||
|
|
|
@ -6,6 +6,8 @@ import cc.ryanc.halo.exception.NotFoundException;
|
||||||
import cc.ryanc.halo.model.entity.User;
|
import cc.ryanc.halo.model.entity.User;
|
||||||
import cc.ryanc.halo.model.params.UserParam;
|
import cc.ryanc.halo.model.params.UserParam;
|
||||||
import cc.ryanc.halo.repository.UserRepository;
|
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.UserService;
|
||||||
import cc.ryanc.halo.service.base.AbstractCrudService;
|
import cc.ryanc.halo.service.base.AbstractCrudService;
|
||||||
import cc.ryanc.halo.utils.DateUtils;
|
import cc.ryanc.halo.utils.DateUtils;
|
||||||
|
@ -15,6 +17,7 @@ import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -72,9 +75,10 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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(key, "Username or email must not be blank");
|
||||||
Assert.hasText(password, "Password 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
|
// Ger user by username
|
||||||
User user = Validator.isEmail(key) ? getByEmailOfNonNull(key) : getByUsernameOfNonNull(key);
|
User user = Validator.isEmail(key) ? getByEmailOfNonNull(key) : getByUsernameOfNonNull(key);
|
||||||
|
@ -105,7 +109,8 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
||||||
throw new BadRequestException("账号或者密码错误,您还有" + (MAX_LOGIN_TRY - loginFailureCount) + "次机会");
|
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;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
package cc.ryanc.halo.web.controller.admin.api;
|
package cc.ryanc.halo.web.controller.admin.api;
|
||||||
|
|
||||||
import cc.ryanc.halo.model.dto.CountOutputDTO;
|
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.BlogProperties;
|
||||||
import cc.ryanc.halo.model.enums.PostStatus;
|
import cc.ryanc.halo.model.enums.PostStatus;
|
||||||
import cc.ryanc.halo.model.enums.PostType;
|
import cc.ryanc.halo.model.params.LoginParam;
|
||||||
import cc.ryanc.halo.service.AttachmentService;
|
import cc.ryanc.halo.service.*;
|
||||||
import cc.ryanc.halo.service.CommentService;
|
|
||||||
import cc.ryanc.halo.service.OptionService;
|
|
||||||
import cc.ryanc.halo.service.PostService;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin controller.
|
* Admin controller.
|
||||||
|
@ -31,11 +31,18 @@ public class AdminController {
|
||||||
|
|
||||||
private final OptionService optionService;
|
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.postService = postService;
|
||||||
this.attachmentService = attachmentService;
|
this.attachmentService = attachmentService;
|
||||||
this.commentService = commentService;
|
this.commentService = commentService;
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("counts")
|
@GetMapping("counts")
|
||||||
|
@ -48,4 +55,10 @@ public class AdminController {
|
||||||
countOutputDTO.setEstablishDays(Long.valueOf(optionService.getByProperty(BlogProperties.WIDGET_DAYCOUNT).orElse("0")));
|
countOutputDTO.setEstablishDays(Long.valueOf(optionService.getByProperty(BlogProperties.WIDGET_DAYCOUNT).orElse("0")));
|
||||||
return countOutputDTO;
|
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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue