调整登录代码逻辑,解决发现的问题
This commit is contained in:
parent
6eb7f5dd7d
commit
c8a662c5fd
@ -4,12 +4,16 @@ import ink.wgink.pojo.dtos.department.DepartmentSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.group.GroupSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.position.PositionSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.role.RoleSimpleDTO;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @ClassName: UserBO
|
||||
@ -18,7 +22,19 @@ import java.util.List;
|
||||
* @Date: 2019/2/20 2:22 PM
|
||||
* @Version: 1.0
|
||||
**/
|
||||
public class LoginUser extends User {
|
||||
public class LoginUser implements UserDetails, CredentialsContainer {
|
||||
|
||||
/**
|
||||
* org.springframework.security.core.userdetails.user的属性
|
||||
*/
|
||||
private static final long serialVersionUID = 1399973719726626183L;
|
||||
private String password;
|
||||
private final String username;
|
||||
private final boolean accountNonExpired;
|
||||
private final boolean accountNonLocked;
|
||||
private final boolean credentialsNonExpired;
|
||||
private Set<GrantedAuthority> authorities;
|
||||
private final boolean enabled;
|
||||
|
||||
private String userId;
|
||||
private String userName;
|
||||
@ -39,16 +55,218 @@ public class LoginUser extends User {
|
||||
*/
|
||||
private Object expandData;
|
||||
|
||||
public LoginUser() {
|
||||
super("", "", null);
|
||||
public LoginUser(String username, String password) {
|
||||
this(username, password, true, true, true, true);
|
||||
}
|
||||
|
||||
public LoginUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, authorities);
|
||||
public LoginUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked) {
|
||||
if (username != null && !"".equals(username) && password != null) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.enabled = enabled;
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
|
||||
}
|
||||
}
|
||||
|
||||
public LoginUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
||||
// this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
this.authorities = sortAuthorities(authorities);
|
||||
}
|
||||
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return this.authorities;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.accountNonExpired;
|
||||
}
|
||||
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.accountNonLocked;
|
||||
}
|
||||
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.credentialsNonExpired;
|
||||
}
|
||||
|
||||
public void eraseCredentials() {
|
||||
this.password = null;
|
||||
}
|
||||
|
||||
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet(new LoginUser.AuthorityComparator());
|
||||
Iterator iterator = authorities.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
GrantedAuthority grantedAuthority = (GrantedAuthority) iterator.next();
|
||||
sortedAuthorities.add(grantedAuthority);
|
||||
}
|
||||
|
||||
return sortedAuthorities;
|
||||
}
|
||||
|
||||
public boolean equals(Object rhs) {
|
||||
return rhs instanceof User ? this.username.equals(((LoginUser) rhs).username) : false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.username.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString()).append(": ");
|
||||
sb.append("Username: ").append(this.username).append("; ");
|
||||
sb.append("Password: [PROTECTED]; ");
|
||||
sb.append("Enabled: ").append(this.enabled).append("; ");
|
||||
sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
|
||||
sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
|
||||
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
|
||||
if (!this.authorities.isEmpty()) {
|
||||
sb.append("Granted Authorities: ");
|
||||
boolean first = true;
|
||||
Iterator var3 = this.authorities.iterator();
|
||||
|
||||
while (var3.hasNext()) {
|
||||
GrantedAuthority auth = (GrantedAuthority) var3.next();
|
||||
if (!first) {
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
first = false;
|
||||
sb.append(auth);
|
||||
}
|
||||
} else {
|
||||
sb.append("Not granted any authorities");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static LoginUser.UserBuilder withUsername(String username) {
|
||||
return builder().username(username);
|
||||
}
|
||||
|
||||
public static LoginUser.UserBuilder builder() {
|
||||
return new LoginUser.UserBuilder();
|
||||
}
|
||||
|
||||
public static LoginUser.UserBuilder withUserDetails(UserDetails userDetails) {
|
||||
return withUsername(userDetails.getUsername()).password(userDetails.getPassword()).accountExpired(!userDetails.isAccountNonExpired()).accountLocked(!userDetails.isAccountNonLocked()).authorities(userDetails.getAuthorities()).credentialsExpired(!userDetails.isCredentialsNonExpired()).disabled(!userDetails.isEnabled());
|
||||
}
|
||||
|
||||
public static class UserBuilder {
|
||||
private String username;
|
||||
private String password;
|
||||
private List<GrantedAuthority> authorities;
|
||||
private boolean accountExpired;
|
||||
private boolean accountLocked;
|
||||
private boolean credentialsExpired;
|
||||
private boolean disabled;
|
||||
private Function<String, String> passwordEncoder;
|
||||
|
||||
private UserBuilder() {
|
||||
this.passwordEncoder = (password) -> {
|
||||
return password;
|
||||
};
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder username(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder password(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder passwordEncoder(Function<String, String> encoder) {
|
||||
this.passwordEncoder = encoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder roles(String... roles) {
|
||||
List<GrantedAuthority> authorities = new ArrayList(roles.length);
|
||||
String[] var3 = roles;
|
||||
int var4 = roles.length;
|
||||
|
||||
for (int var5 = 0; var5 < var4; ++var5) {
|
||||
String role = var3[var5];
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
|
||||
}
|
||||
|
||||
return this.authorities((Collection) authorities);
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder authorities(GrantedAuthority... authorities) {
|
||||
return this.authorities((Collection) Arrays.asList(authorities));
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
this.authorities = new ArrayList(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder authorities(String... authorities) {
|
||||
return this.authorities((Collection) AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder accountExpired(boolean accountExpired) {
|
||||
this.accountExpired = accountExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder accountLocked(boolean accountLocked) {
|
||||
this.accountLocked = accountLocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder credentialsExpired(boolean credentialsExpired) {
|
||||
this.credentialsExpired = credentialsExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder disabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetails build() {
|
||||
String encodedPassword = (String) this.passwordEncoder.apply(this.password);
|
||||
return new User(this.username, encodedPassword, !this.disabled, !this.accountExpired, !this.credentialsExpired, !this.accountLocked, this.authorities);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
|
||||
private static final long serialVersionUID = 510L;
|
||||
|
||||
private AuthorityComparator() {
|
||||
}
|
||||
|
||||
public int compare(GrantedAuthority g1, GrantedAuthority g2) {
|
||||
if (g2.getAuthority() == null) {
|
||||
return -1;
|
||||
} else {
|
||||
return g1.getAuthority() == null ? 1 : g1.getAuthority().compareTo(g2.getAuthority());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
@ -171,4 +389,5 @@ public class LoginUser extends User {
|
||||
public void setExpandData(Object expandData) {
|
||||
this.expandData = expandData;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,17 +1,44 @@
|
||||
package ink.wgink.login.base.authentication.user;
|
||||
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
|
||||
import ink.wgink.interfaces.group.IGroupUserBaseService;
|
||||
import ink.wgink.interfaces.position.IPositionUserBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleMenuBaseService;
|
||||
import ink.wgink.interfaces.role.IRolePermissionBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleUserBaseService;
|
||||
import ink.wgink.login.base.consts.IUserCenterConst;
|
||||
import ink.wgink.login.base.enums.LoginTypeEnum;
|
||||
import ink.wgink.login.base.exceptions.UserAuthenticationException;
|
||||
import ink.wgink.login.base.service.user.UserLoginService;
|
||||
import ink.wgink.pojo.bos.LoginUser;
|
||||
import ink.wgink.pojo.bos.RoleGrantedAuthorityBO;
|
||||
import ink.wgink.pojo.dtos.department.DepartmentSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.group.GroupSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.position.PositionSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.role.RoleSimpleDTO;
|
||||
import ink.wgink.pojo.pos.DepartmentPO;
|
||||
import ink.wgink.pojo.pos.GroupPO;
|
||||
import ink.wgink.pojo.pos.PositionPO;
|
||||
import ink.wgink.pojo.pos.RolePO;
|
||||
import ink.wgink.properties.AccessControlProperties;
|
||||
import ink.wgink.service.department.service.IDepartmentUserService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
@ -23,27 +50,158 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
* @Version: 1.0
|
||||
**/
|
||||
public class UserAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UserAuthenticationProvider.class);
|
||||
private UserDetailsService userDetailsService;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
private UserLoginService userLoginService;
|
||||
private IRoleUserBaseService roleUserBaseService;
|
||||
private IRoleMenuBaseService roleMenuBaseService;
|
||||
private IRolePermissionBaseService rolePermissionService;
|
||||
private IGroupUserBaseService groupUserBaseService;
|
||||
private IPositionUserBaseService positionUserBaseService;
|
||||
private ILoginHandlerService loginHandler;
|
||||
private IDepartmentUserService departmentUserService;
|
||||
private AccessControlProperties accessControlProperties;
|
||||
private HttpSession httpSession;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
UserAuthenticationToken userAuthenticationToken = (UserAuthenticationToken) authentication;
|
||||
LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(userAuthenticationToken.getPrincipal().toString());
|
||||
String username = userAuthenticationToken.getPrincipal().toString();
|
||||
httpSession.setAttribute(IUserCenterConst.LOGIN_USERNAME, username);
|
||||
LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(username);
|
||||
if (!passwordEncoder.matches(userAuthenticationToken.getCredentials().toString(), loginUser.getPassword())) {
|
||||
throw new UserAuthenticationException("用户名或密码错误");
|
||||
}
|
||||
// 清空session中的错误信息
|
||||
httpSession.removeAttribute(IUserCenterConst.ERROR_MESSAGE);
|
||||
httpSession.removeAttribute(IUserCenterConst.LOGIN_USERNAME);
|
||||
LOG.debug("设置权限权限");
|
||||
Set<GrantedAuthority> grantedAuthorities = new LinkedHashSet<>();
|
||||
if (StringUtils.equalsIgnoreCase(ISystemConstant.ADMIN, loginUser.getUsername())) {
|
||||
grantedAuthorities.add(new RoleGrantedAuthorityBO(ISystemConstant.ADMIN));
|
||||
} else {
|
||||
List<RolePO> rolePOs = null;
|
||||
// 先处理授权,再创建对象,否则 grantedAuthorities 中无法赋值
|
||||
if (roleUserBaseService != null) {
|
||||
LOG.debug("设置角色信息");
|
||||
rolePOs = roleUserBaseService.listRolePOByUserId(loginUser.getUserId());
|
||||
removalDuplicateRole(rolePOs);
|
||||
grantedAuthorities.addAll(loadRoleAuthority(rolePOs));
|
||||
if (grantedAuthorities.isEmpty()) {
|
||||
throw new UserAuthenticationException(loginUser.getUsername() + "用户无任何角色");
|
||||
}
|
||||
}
|
||||
|
||||
if (rolePOs != null) {
|
||||
List<RoleSimpleDTO> roleSimpleDTOs = roleUserBaseService.listSimple(rolePOs);
|
||||
loginUser.setRoles(roleSimpleDTOs);
|
||||
}
|
||||
|
||||
LOG.debug("设置部门状态");
|
||||
List<DepartmentPO> departmentPOs = departmentUserService.listDepartmentPOByUserId(loginUser.getUserId());
|
||||
List<DepartmentSimpleDTO> departmentSimpleDTOs = departmentUserService.listSimple(departmentPOs);
|
||||
loginUser.setDepartments(departmentSimpleDTOs);
|
||||
|
||||
if (groupUserBaseService != null) {
|
||||
LOG.debug("设置组信息");
|
||||
List<GroupPO> groupPOs = groupUserBaseService.listGroupPOByUserId(loginUser.getUserId());
|
||||
List<GroupSimpleDTO> groupSimpleDTOs = groupUserBaseService.listSimple(groupPOs);
|
||||
loginUser.setGroups(groupSimpleDTOs);
|
||||
}
|
||||
if (positionUserBaseService != null) {
|
||||
LOG.debug("设置职位");
|
||||
List<PositionPO> positionPOs = positionUserBaseService.listPositionPOByUserId(loginUser.getUserId());
|
||||
List<PositionSimpleDTO> positionSimpleDTOs = positionUserBaseService.listSimple(positionPOs);
|
||||
loginUser.setPositions(positionSimpleDTOs);
|
||||
}
|
||||
}
|
||||
// 设置权限
|
||||
loginUser.setAuthorities(grantedAuthorities);
|
||||
loginHandler(loginUser);
|
||||
// 设置数据权限
|
||||
if (!StringUtils.equalsIgnoreCase(ISystemConstant.ADMIN, loginUser.getUsername())) {
|
||||
userLoginService.setUserDataAuthority(loginUser);
|
||||
}
|
||||
// 更新登录信息
|
||||
userLoginService.updateUserLoginInfo(loginUser.getUserId(), loginUser.getUserName(), LoginTypeEnum.USERNAME_AND_PASSWORD.getValue());
|
||||
UserAuthenticationToken userAuthenticationTokenResult = new UserAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
||||
userAuthenticationTokenResult.setDetails(userAuthenticationToken.getDetails());
|
||||
return userAuthenticationTokenResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录处理
|
||||
*
|
||||
* @param loginUser
|
||||
*/
|
||||
private void loginHandler(LoginUser loginUser) {
|
||||
if (loginHandler != null) {
|
||||
try {
|
||||
loginHandler.handle(loginUser);
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
throw new UserAuthenticationException("登录异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 角色授权列表
|
||||
*
|
||||
* @param rolePOs
|
||||
* @return
|
||||
*/
|
||||
private List<GrantedAuthority> loadRoleAuthority(List<RolePO> rolePOs) {
|
||||
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
if (null != rolePOs && !rolePOs.isEmpty()) {
|
||||
// 设置菜单权限
|
||||
rolePOs.forEach((rolePO) -> {
|
||||
List<String> menuUrls = roleMenuBaseService.listMenuUrl(rolePO.getRoleId());
|
||||
List<String> inserts = new ArrayList<>();
|
||||
List<String> deletes = new ArrayList<>();
|
||||
List<String> updates = new ArrayList<>();
|
||||
List<String> queries = new ArrayList<>();
|
||||
if (accessControlProperties.getRolePermission()) {
|
||||
inserts.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_INSERT));
|
||||
deletes.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_DELETE));
|
||||
updates.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_UPDATE));
|
||||
queries.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_QUERY));
|
||||
}
|
||||
grantedAuthorities.add(new RoleGrantedAuthorityBO(rolePO.getRoleId(), rolePO.getRoleName(), menuUrls, inserts, deletes, updates, queries));
|
||||
});
|
||||
|
||||
}
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除重复的角色
|
||||
*
|
||||
* @param rolePOs
|
||||
*/
|
||||
private void removalDuplicateRole(List<RolePO> rolePOs) {
|
||||
if (rolePOs == null || rolePOs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < rolePOs.size(); i++) {
|
||||
RolePO rolePO = rolePOs.get(i);
|
||||
boolean isExist = false;
|
||||
for (int j = i + 1; j < rolePOs.size(); j++) {
|
||||
if (StringUtils.equals(rolePO.getRoleId(), rolePOs.get(j).getRoleId())) {
|
||||
isExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExist) {
|
||||
rolePOs.remove(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return UserAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
@ -60,4 +218,40 @@ public class UserAuthenticationProvider implements AuthenticationProvider {
|
||||
public void setUserLoginService(UserLoginService userLoginService) {
|
||||
this.userLoginService = userLoginService;
|
||||
}
|
||||
|
||||
public void setRoleUserBaseService(IRoleUserBaseService roleUserBaseService) {
|
||||
this.roleUserBaseService = roleUserBaseService;
|
||||
}
|
||||
|
||||
public void setRoleMenuBaseService(IRoleMenuBaseService roleMenuBaseService) {
|
||||
this.roleMenuBaseService = roleMenuBaseService;
|
||||
}
|
||||
|
||||
public void setRolePermissionService(IRolePermissionBaseService rolePermissionService) {
|
||||
this.rolePermissionService = rolePermissionService;
|
||||
}
|
||||
|
||||
public void setGroupUserBaseService(IGroupUserBaseService groupUserBaseService) {
|
||||
this.groupUserBaseService = groupUserBaseService;
|
||||
}
|
||||
|
||||
public void setPositionUserBaseService(IPositionUserBaseService positionUserBaseService) {
|
||||
this.positionUserBaseService = positionUserBaseService;
|
||||
}
|
||||
|
||||
public void setLoginHandler(ILoginHandlerService loginHandler) {
|
||||
this.loginHandler = loginHandler;
|
||||
}
|
||||
|
||||
public void setDepartmentUserService(IDepartmentUserService departmentUserService) {
|
||||
this.departmentUserService = departmentUserService;
|
||||
}
|
||||
|
||||
public void setAccessControlProperties(AccessControlProperties accessControlProperties) {
|
||||
this.accessControlProperties = accessControlProperties;
|
||||
}
|
||||
|
||||
public void setHttpSession(HttpSession httpSession) {
|
||||
this.httpSession = httpSession;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ package ink.wgink.login.base.consts;
|
||||
public interface IUserCenterConst {
|
||||
|
||||
String ERROR = "error";
|
||||
String LOGIN_USERNAME = "loginUsername";
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
|
@ -1,12 +1,20 @@
|
||||
package ink.wgink.login.base.security;
|
||||
|
||||
import ink.wgink.common.handler.AccessDenyHandler;
|
||||
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
|
||||
import ink.wgink.interfaces.group.IGroupUserBaseService;
|
||||
import ink.wgink.interfaces.position.IPositionUserBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleMenuBaseService;
|
||||
import ink.wgink.interfaces.role.IRolePermissionBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleUserBaseService;
|
||||
import ink.wgink.login.base.handler.LoginFailureHandler;
|
||||
import ink.wgink.login.base.handler.LogoutHandler;
|
||||
import ink.wgink.login.base.security.user.UserSecurityConfig;
|
||||
import ink.wgink.login.base.service.user.UserDetailServiceImpl;
|
||||
import ink.wgink.login.base.service.user.UserLoginService;
|
||||
import ink.wgink.properties.AccessControlProperties;
|
||||
import ink.wgink.properties.BaseProperties;
|
||||
import ink.wgink.service.department.service.IDepartmentUserService;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -18,6 +26,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @ClassName: WebSecurityConfig
|
||||
* @Description: security配置
|
||||
@ -34,6 +44,24 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
private UserDetailServiceImpl userDetailService;
|
||||
@Autowired
|
||||
private UserLoginService userLoginService;
|
||||
@Autowired(required = false)
|
||||
private IRoleUserBaseService roleUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private IRoleMenuBaseService roleMenuBaseService;
|
||||
@Autowired(required = false)
|
||||
private IRolePermissionBaseService rolePermissionService;
|
||||
@Autowired(required = false)
|
||||
private IGroupUserBaseService groupUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private IPositionUserBaseService positionUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private ILoginHandlerService loginHandler;
|
||||
@Autowired
|
||||
private IDepartmentUserService departmentUserService;
|
||||
@Autowired
|
||||
private AccessControlProperties accessControlProperties;
|
||||
@Autowired
|
||||
private HttpSession httpSession;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@ -107,6 +135,15 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
userSecurityConfig.setLoginProcessUrl(baseProperties.getLoginProcess());
|
||||
userSecurityConfig.setLoginFailureHandler(loginFailureHandler);
|
||||
userSecurityConfig.setUserLoginService(userLoginService);
|
||||
userSecurityConfig.setRoleUserBaseService(roleUserBaseService);
|
||||
userSecurityConfig.setRoleMenuBaseService(roleMenuBaseService);
|
||||
userSecurityConfig.setRolePermissionService(rolePermissionService);
|
||||
userSecurityConfig.setGroupUserBaseService(groupUserBaseService);
|
||||
userSecurityConfig.setPositionUserBaseService(positionUserBaseService);
|
||||
userSecurityConfig.setLoginHandler(loginHandler);
|
||||
userSecurityConfig.setDepartmentUserService(departmentUserService);
|
||||
userSecurityConfig.setAccessControlProperties(accessControlProperties);
|
||||
userSecurityConfig.setHttpSession(httpSession);
|
||||
http.apply(userSecurityConfig);
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,18 @@
|
||||
package ink.wgink.login.base.security.user;
|
||||
|
||||
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
|
||||
import ink.wgink.interfaces.group.IGroupUserBaseService;
|
||||
import ink.wgink.interfaces.position.IPositionUserBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleMenuBaseService;
|
||||
import ink.wgink.interfaces.role.IRolePermissionBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleUserBaseService;
|
||||
import ink.wgink.login.base.authentication.user.UserAuthenticationFilter;
|
||||
import ink.wgink.login.base.authentication.user.UserAuthenticationProvider;
|
||||
import ink.wgink.login.base.handler.LoginFailureHandler;
|
||||
import ink.wgink.login.base.service.user.UserDetailServiceImpl;
|
||||
import ink.wgink.login.base.service.user.UserLoginService;
|
||||
import ink.wgink.properties.AccessControlProperties;
|
||||
import ink.wgink.service.department.service.IDepartmentUserService;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -12,6 +20,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
@ -29,6 +39,15 @@ public class UserSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurit
|
||||
private String loginProcessUrl;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
private UserLoginService userLoginService;
|
||||
private IRoleUserBaseService roleUserBaseService;
|
||||
private IRoleMenuBaseService roleMenuBaseService;
|
||||
private IRolePermissionBaseService rolePermissionService;
|
||||
private IGroupUserBaseService groupUserBaseService;
|
||||
private IPositionUserBaseService positionUserBaseService;
|
||||
private ILoginHandlerService loginHandler;
|
||||
private IDepartmentUserService departmentUserService;
|
||||
private AccessControlProperties accessControlProperties;
|
||||
private HttpSession httpSession;
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
@ -42,6 +61,15 @@ public class UserSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurit
|
||||
userAuthenticationProvider.setPasswordEncoder(passwordEncoder);
|
||||
userAuthenticationProvider.setUserDetailsService(userDetailService);
|
||||
userAuthenticationProvider.setUserLoginService(userLoginService);
|
||||
userAuthenticationProvider.setRoleUserBaseService(roleUserBaseService);
|
||||
userAuthenticationProvider.setRoleMenuBaseService(roleMenuBaseService);
|
||||
userAuthenticationProvider.setRolePermissionService(rolePermissionService);
|
||||
userAuthenticationProvider.setGroupUserBaseService(groupUserBaseService);
|
||||
userAuthenticationProvider.setPositionUserBaseService(positionUserBaseService);
|
||||
userAuthenticationProvider.setLoginHandler(loginHandler);
|
||||
userAuthenticationProvider.setDepartmentUserService(departmentUserService);
|
||||
userAuthenticationProvider.setAccessControlProperties(accessControlProperties);
|
||||
userAuthenticationProvider.setHttpSession(httpSession);
|
||||
// 加入SpringSecurity的authentication管理的provider集合当中,并且添加到UsernamePasswordAuthenticationFilter之前
|
||||
http.authenticationProvider(userAuthenticationProvider).addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
@ -65,4 +93,40 @@ public class UserSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurit
|
||||
public void setUserLoginService(UserLoginService userLoginService) {
|
||||
this.userLoginService = userLoginService;
|
||||
}
|
||||
|
||||
public void setRoleUserBaseService(IRoleUserBaseService roleUserBaseService) {
|
||||
this.roleUserBaseService = roleUserBaseService;
|
||||
}
|
||||
|
||||
public void setRoleMenuBaseService(IRoleMenuBaseService roleMenuBaseService) {
|
||||
this.roleMenuBaseService = roleMenuBaseService;
|
||||
}
|
||||
|
||||
public void setRolePermissionService(IRolePermissionBaseService rolePermissionService) {
|
||||
this.rolePermissionService = rolePermissionService;
|
||||
}
|
||||
|
||||
public void setGroupUserBaseService(IGroupUserBaseService groupUserBaseService) {
|
||||
this.groupUserBaseService = groupUserBaseService;
|
||||
}
|
||||
|
||||
public void setPositionUserBaseService(IPositionUserBaseService positionUserBaseService) {
|
||||
this.positionUserBaseService = positionUserBaseService;
|
||||
}
|
||||
|
||||
public void setLoginHandler(ILoginHandlerService loginHandler) {
|
||||
this.loginHandler = loginHandler;
|
||||
}
|
||||
|
||||
public void setDepartmentUserService(IDepartmentUserService departmentUserService) {
|
||||
this.departmentUserService = departmentUserService;
|
||||
}
|
||||
|
||||
public void setAccessControlProperties(AccessControlProperties accessControlProperties) {
|
||||
this.accessControlProperties = accessControlProperties;
|
||||
}
|
||||
|
||||
public void setHttpSession(HttpSession httpSession) {
|
||||
this.httpSession = httpSession;
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ public class OAuthServiceImpl implements IOAuthService {
|
||||
Map<String, Object> config = ConfigManager.getInstance().getConfig();
|
||||
Map<String, Object> pageParams = new HashMap<>(16);
|
||||
pageParams.put(IUserCenterConst.ERROR_MESSAGE, request.getSession().getAttribute(IUserCenterConst.ERROR_MESSAGE));
|
||||
pageParams.put(IUserCenterConst.LOGIN_USERNAME, request.getSession().getAttribute(IUserCenterConst.LOGIN_USERNAME));
|
||||
// 服务地址
|
||||
pageParams.put(IUserCenterConst.SERVER_URL, serverProperties.getUrl());
|
||||
// 系统LOGO
|
||||
|
@ -46,6 +46,7 @@ public class LoginFormServiceImpl extends DefaultBaseService implements ILoginFo
|
||||
public void remove(List<String> loginFormIds) {
|
||||
Map<String, Object> params = getHashMap(2);
|
||||
params.put("loginFormIds", loginFormIds);
|
||||
setUpdateInfo(params);
|
||||
loginFormDao.remove(params);
|
||||
}
|
||||
|
||||
|
@ -2,44 +2,22 @@ package ink.wgink.login.base.service.user;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
|
||||
import ink.wgink.interfaces.group.IGroupUserBaseService;
|
||||
import ink.wgink.interfaces.position.IPositionUserBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleMenuBaseService;
|
||||
import ink.wgink.interfaces.role.IRolePermissionBaseService;
|
||||
import ink.wgink.interfaces.role.IRoleUserBaseService;
|
||||
import ink.wgink.interfaces.user.IUserDetailCheckService;
|
||||
import ink.wgink.login.base.consts.IUserCenterConst;
|
||||
import ink.wgink.login.base.exceptions.UserAuthenticationException;
|
||||
import ink.wgink.login.base.manager.ConfigManager;
|
||||
import ink.wgink.pojo.bos.LoginUser;
|
||||
import ink.wgink.pojo.bos.RoleGrantedAuthorityBO;
|
||||
import ink.wgink.pojo.dtos.department.DepartmentSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.group.GroupSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.position.PositionSimpleDTO;
|
||||
import ink.wgink.pojo.dtos.role.RoleSimpleDTO;
|
||||
import ink.wgink.pojo.pos.DepartmentPO;
|
||||
import ink.wgink.pojo.pos.GroupPO;
|
||||
import ink.wgink.pojo.pos.PositionPO;
|
||||
import ink.wgink.pojo.pos.RolePO;
|
||||
import ink.wgink.properties.AccessControlProperties;
|
||||
import ink.wgink.service.department.service.IDepartmentUserService;
|
||||
import ink.wgink.service.user.pojo.pos.UserPO;
|
||||
import ink.wgink.service.user.service.IUserService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: UserDetailServiceImpl
|
||||
@ -51,28 +29,8 @@ import java.util.*;
|
||||
@Service
|
||||
public class UserDetailServiceImpl implements UserDetailsService, IUserDetailCheckService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UserDetailServiceImpl.class);
|
||||
|
||||
@Autowired(required = false)
|
||||
private IRoleUserBaseService roleUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private IRoleMenuBaseService roleMenuBaseService;
|
||||
@Autowired(required = false)
|
||||
private IRolePermissionBaseService rolePermissionService;
|
||||
@Autowired(required = false)
|
||||
private IGroupUserBaseService groupUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private IPositionUserBaseService positionUserBaseService;
|
||||
@Autowired(required = false)
|
||||
private ILoginHandlerService loginHandler;
|
||||
@Autowired
|
||||
private IDepartmentUserService departmentUserService;
|
||||
@Autowired
|
||||
private IUserService userService;
|
||||
@Autowired
|
||||
private AccessControlProperties accessControlProperties;
|
||||
@Autowired
|
||||
private HttpSession httpSession;
|
||||
|
||||
public UserDetailServiceImpl() {
|
||||
super();
|
||||
@ -95,85 +53,24 @@ public class UserDetailServiceImpl implements UserDetailsService, IUserDetailChe
|
||||
if (userPO.getUserState() == 1) {
|
||||
throw new UserAuthenticationException("账号已冻结");
|
||||
}
|
||||
|
||||
LOG.debug("设置权限权限");
|
||||
LoginUser loginUser;
|
||||
Set<GrantedAuthority> grantedAuthorities = new LinkedHashSet<>();
|
||||
if (StringUtils.equalsIgnoreCase(ISystemConstant.ADMIN, username)) {
|
||||
grantedAuthorities.add(new RoleGrantedAuthorityBO(ISystemConstant.ADMIN));
|
||||
loginUser = createUserBO(userPO, grantedAuthorities);
|
||||
} else {
|
||||
List<RolePO> rolePOs = null;
|
||||
// 先处理授权,再创建对象,否则 grantedAuthorities 中无法赋值
|
||||
if (roleUserBaseService != null) {
|
||||
LOG.debug("设置角色信息");
|
||||
rolePOs = roleUserBaseService.listRolePOByUserId(userPO.getUserId());
|
||||
removalDuplicateRole(rolePOs);
|
||||
grantedAuthorities.addAll(loadRoleAuthority(rolePOs));
|
||||
if (grantedAuthorities.isEmpty()) {
|
||||
throw new UserAuthenticationException(username + "用户无任何角色");
|
||||
}
|
||||
}
|
||||
|
||||
loginUser = createUserBO(userPO, grantedAuthorities);
|
||||
if (rolePOs != null) {
|
||||
List<RoleSimpleDTO> roleSimpleDTOs = roleUserBaseService.listSimple(rolePOs);
|
||||
loginUser.setRoles(roleSimpleDTOs);
|
||||
}
|
||||
|
||||
LOG.debug("设置部门状态");
|
||||
List<DepartmentPO> departmentPOs = departmentUserService.listDepartmentPOByUserId(userPO.getUserId());
|
||||
List<DepartmentSimpleDTO> departmentSimpleDTOs = departmentUserService.listSimple(departmentPOs);
|
||||
loginUser.setDepartments(departmentSimpleDTOs);
|
||||
|
||||
if (groupUserBaseService != null) {
|
||||
LOG.debug("设置组信息");
|
||||
List<GroupPO> groupPOs = groupUserBaseService.listGroupPOByUserId(userPO.getUserId());
|
||||
List<GroupSimpleDTO> groupSimpleDTOs = groupUserBaseService.listSimple(groupPOs);
|
||||
loginUser.setGroups(groupSimpleDTOs);
|
||||
}
|
||||
if (positionUserBaseService != null) {
|
||||
LOG.debug("设置职位");
|
||||
List<PositionPO> positionPOs = positionUserBaseService.listPositionPOByUserId(userPO.getUserId());
|
||||
List<PositionSimpleDTO> positionSimpleDTOs = positionUserBaseService.listSimple(positionPOs);
|
||||
loginUser.setPositions(positionSimpleDTOs);
|
||||
}
|
||||
}
|
||||
loginHandler(loginUser);
|
||||
// 清空session中的错误信息
|
||||
httpSession.removeAttribute(IUserCenterConst.ERROR_MESSAGE);
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录处理
|
||||
*
|
||||
* @param loginUser
|
||||
*/
|
||||
private void loginHandler(LoginUser loginUser) {
|
||||
if (loginHandler != null) {
|
||||
try {
|
||||
loginHandler.handle(loginUser);
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
throw new UserAuthenticationException("登录异常");
|
||||
}
|
||||
if (isAccountExpired(userPO)) {
|
||||
throw new UserAuthenticationException("账号已经过期");
|
||||
}
|
||||
return createUserBO(userPO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建UserBO
|
||||
*
|
||||
* @param userPO
|
||||
* @param grantedAuthorities
|
||||
* @return
|
||||
*/
|
||||
private LoginUser createUserBO(UserPO userPO, Set<GrantedAuthority> grantedAuthorities) {
|
||||
private LoginUser createUserBO(UserPO userPO) {
|
||||
LoginUser loginUser = new LoginUser(userPO.getUserUsername(), userPO.getUserPassword(),
|
||||
userPO.getUserType() == 1 ? true : false,
|
||||
isAccountNonExpired(userPO),
|
||||
isCredentialsNonExpired(userPO),
|
||||
userPO.getUserState() == 0 ? true : false, grantedAuthorities);
|
||||
userPO.getUserState() == 0 ? true : false);
|
||||
loginUser.setUserId(userPO.getUserId());
|
||||
loginUser.setUserName(userPO.getUserName());
|
||||
loginUser.setUserPhone(userPO.getUserPhone());
|
||||
@ -235,58 +132,21 @@ public class UserDetailServiceImpl implements UserDetailsService, IUserDetailChe
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色授权列表
|
||||
* 账号是否过期
|
||||
*
|
||||
* @param rolePOs
|
||||
* @param userPO
|
||||
* @return
|
||||
*/
|
||||
private List<GrantedAuthority> loadRoleAuthority(List<RolePO> rolePOs) {
|
||||
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
if (null != rolePOs && !rolePOs.isEmpty()) {
|
||||
// 设置菜单权限
|
||||
rolePOs.forEach((rolePO) -> {
|
||||
List<String> menuUrls = roleMenuBaseService.listMenuUrl(rolePO.getRoleId());
|
||||
List<String> inserts = new ArrayList<>();
|
||||
List<String> deletes = new ArrayList<>();
|
||||
List<String> updates = new ArrayList<>();
|
||||
List<String> queries = new ArrayList<>();
|
||||
if (accessControlProperties.getRolePermission()) {
|
||||
inserts.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_INSERT));
|
||||
deletes.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_DELETE));
|
||||
updates.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_UPDATE));
|
||||
queries.addAll(rolePermissionService.listPermissionUrl(rolePO.getRoleId(), IRolePermissionBaseService.PERMISSION_QUERY));
|
||||
}
|
||||
grantedAuthorities.add(new RoleGrantedAuthorityBO(rolePO.getRoleId(), rolePO.getRoleName(), menuUrls, inserts, deletes, updates, queries));
|
||||
});
|
||||
|
||||
private boolean isAccountExpired(UserPO userPO) {
|
||||
if (StringUtils.isBlank(userPO.getUserExpiredDate())) {
|
||||
return false;
|
||||
}
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除重复的角色
|
||||
*
|
||||
* @param rolePOs
|
||||
*/
|
||||
private void removalDuplicateRole(List<RolePO> rolePOs) {
|
||||
if (rolePOs == null || rolePOs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < rolePOs.size(); i++) {
|
||||
RolePO rolePO = rolePOs.get(i);
|
||||
boolean isExist = false;
|
||||
for (int j = i + 1; j < rolePOs.size(); j++) {
|
||||
if (StringUtils.equals(rolePO.getRoleId(), rolePOs.get(j).getRoleId())) {
|
||||
isExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isExist) {
|
||||
rolePOs.remove(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
DateTime now = DateTime.now();
|
||||
DateTime expiredDateTime = DateTime.parse(userPO.getUserExpiredDate(), DateTimeFormat.forPattern(ISystemConstant.DATE_FORMATTER_YYYY_MM_DD_HH_MM_SS));
|
||||
if (expiredDateTime.isAfter(now)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -162,6 +162,12 @@
|
||||
gmt_create
|
||||
FROM
|
||||
sys_login_form
|
||||
WHERE
|
||||
is_delete = 0
|
||||
<if test="keywords != null and keywords != ''">
|
||||
AND
|
||||
name LIKE CONCAT('%', #{keywords}, '%')
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 登录form表单详情 -->
|
||||
@ -182,10 +188,13 @@
|
||||
FROM
|
||||
sys_login_form
|
||||
WHERE
|
||||
is_delete = 0
|
||||
<if test="loginFormId != null and loginFormId != ''">
|
||||
AND
|
||||
loginform_id = #{loginFormId}
|
||||
</if>
|
||||
<if test="isActive != null">
|
||||
AND
|
||||
is_active = #{isActive}
|
||||
</if>
|
||||
</select>
|
||||
|
@ -104,13 +104,14 @@
|
||||
var md5 = layui.md5;
|
||||
var base64 = layui.base64;
|
||||
|
||||
var pageParams = [[${pageParams}]];
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
pageParams: [[${pageParams}]],
|
||||
pageParams: pageParams,
|
||||
formData: {
|
||||
verificationCode: '',
|
||||
username: '',
|
||||
username: pageParams.loginUsername,
|
||||
password: '',
|
||||
remember: false
|
||||
}
|
||||
|
@ -28,6 +28,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="departmentNo" type="text" name="departmentNo" placeholder="请输入组织编号" class="layui-input" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称(英文)</label>
|
||||
@ -36,8 +46,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称(其他)</label>
|
||||
@ -46,6 +54,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">组织类型 *</label>
|
||||
|
@ -34,6 +34,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="departmentNo" type="text" name="departmentNo" placeholder="请输入组织编号" class="layui-input" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称(英文)</label>
|
||||
@ -42,8 +52,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称(其他)</label>
|
||||
@ -52,6 +60,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">组织类型 *</label>
|
||||
|
@ -65,7 +65,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="departmentNo" type="text" name="departmentNo" lay-verify="required" placeholder="请输入组织编号" class="layui-input" maxlength="50">
|
||||
<input id="departmentNo" type="text" name="departmentNo" placeholder="请输入组织编号" class="layui-input" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -65,7 +65,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="departmentNo" type="text" name="departmentNo" lay-verify="required" placeholder="请输入组织编号" class="layui-input" maxlength="50">
|
||||
<input id="departmentNo" type="text" name="departmentNo" placeholder="请输入组织编号" class="layui-input" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<body>
|
||||
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2" style="padding-right: 0px">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body left-tree-wrap">
|
||||
<div id="leftTreeWrap">
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10">
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10" style="padding-left: 0px">
|
||||
<div class="layui-card">
|
||||
<div id="listContentWrap" class="layui-card-body">
|
||||
<iframe id="listContent" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<body>
|
||||
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2" style="padding-right: 0px">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body left-tree-wrap">
|
||||
<div id="leftTreeWrap">
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10">
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10" style="padding-left: 0px">
|
||||
<div class="layui-card">
|
||||
<div id="listContentWrap" class="layui-card-body">
|
||||
<iframe id="listContent" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<body>
|
||||
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2" style="padding-right: 0px">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body left-tree-wrap">
|
||||
<div id="leftTreeWrap">
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10">
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10" style="padding-left: 0px">
|
||||
<div class="layui-card">
|
||||
<div id="listContentWrap" class="layui-card-body">
|
||||
<iframe id="listContent" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<body>
|
||||
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2">
|
||||
<div class="layui-col-md2 layui-col-sm2 layui-col-xs2" style="padding-right: 0px">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body left-tree-wrap">
|
||||
<div id="leftTreeWrap">
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10">
|
||||
<div class="layui-col-md10 layui-col-sm10 layui-col-xs10" style="padding-left: 0px">
|
||||
<div class="layui-card">
|
||||
<div id="listContentWrap" class="layui-card-body">
|
||||
<iframe id="listContent" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
|
@ -374,6 +374,14 @@
|
||||
#{excludeUserIds[${index}]}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="startTime != null and startTime != ''">
|
||||
AND
|
||||
LEFT(last_login_time, 10) <![CDATA[ >= ]]> #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null and endTime != ''">
|
||||
AND
|
||||
LEFT(last_login_time, 10) <![CDATA[ <= ]]> #{endTime}
|
||||
</if>
|
||||
<if test="keywords != null and keywords != ''">
|
||||
AND (
|
||||
user_username LIKE CONCAT('%', #{keywords}, '%')
|
||||
|
@ -20,13 +20,14 @@
|
||||
<div class="test-table-reload-btn" style="margin-bottom: 10px;">
|
||||
<input type="hidden" id="userExpand" th:value="${userExpand}" th:if="${userExpand}">
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入关键字">
|
||||
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入用户名、昵称">
|
||||
</div>
|
||||
最后登录
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="startTime" class="layui-input search-item search-item-width-100" placeholder="开始时间" readonly>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="startTime" class="layui-input search-item" placeholder="开始时间" readonly>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="endTime" class="layui-input search-item" placeholder="结束时间" readonly>
|
||||
<input type="text" id="endTime" class="layui-input search-item search-item-width-100" placeholder="结束时间" readonly>
|
||||
</div>
|
||||
<div class="layui-btn-group">
|
||||
<button type="button" id="search" class="layui-btn layui-btn-sm">
|
||||
|
@ -22,70 +22,69 @@
|
||||
<div class="layui-card-body" style="padding: 15px;">
|
||||
<form class="layui-form layui-form-pane" lay-filter="dataForm">
|
||||
<div class="layui-row">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="userPassword" lay-verify="required" placeholder="请输入密码" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">类型 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userType" value="1" title="系统用户">
|
||||
<input type="radio" name="userType" value="2" title="普通用户" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">状态 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userState" value="0" title="正常" checked>
|
||||
<input type="radio" name="userState" value="1" title="锁定">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">过期时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userExpiredDate" id="userExpiredDate" placeholder="请选择过期日期,空表示永不过期" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remarks" placeholder="请输入备注" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-textarea">
|
||||
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
|
||||
<input type="hidden" id="userAvatar" name="userAvatar">
|
||||
<div class="layui-col-md6 layui-col-sm8 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="userPassword" lay-verify="required" placeholder="请输入密码" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">类型 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userType" value="1" title="系统用户">
|
||||
<input type="radio" name="userType" value="2" title="普通用户" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">状态 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userState" value="0" title="正常" checked>
|
||||
<input type="radio" name="userState" value="1" title="锁定">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">过期时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userExpiredDate" id="userExpiredDate" placeholder="请选择过期日期,空表示永不过期" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remarks" placeholder="请输入备注" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2 layui-col-sm4 layui-col-xs12">
|
||||
<div class="layui-form-item" style="text-align: center;">
|
||||
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
|
||||
<input type="hidden" id="userAvatar" name="userAvatar">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-layout-admin">
|
||||
|
@ -22,70 +22,69 @@
|
||||
<div class="layui-card-body" style="padding: 15px;">
|
||||
<form class="layui-form layui-form-pane" lay-filter="dataForm">
|
||||
<div class="layui-row">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="userPassword" placeholder="修改密码,请输入新密码,不修改为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">类型 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userType" value="1" title="系统用户">
|
||||
<input type="radio" name="userType" value="2" title="普通用户">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">状态 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userState" value="0" title="正常">
|
||||
<input type="radio" name="userState" value="1" title="锁定">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">过期时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userExpiredDate" id="userExpiredDate" placeholder="请选择过期日期,空表示永不过期" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remarks" placeholder="请输入备注" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-textarea">
|
||||
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
|
||||
<input type="hidden" id="userAvatar" name="userAvatar">
|
||||
<div class="layui-col-md6 layui-col-sm8 layui-col-xs12">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="userPassword" placeholder="修改密码,请输入新密码,不修改为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">类型 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userType" value="1" title="系统用户">
|
||||
<input type="radio" name="userType" value="2" title="普通用户">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">状态 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="userState" value="0" title="正常">
|
||||
<input type="radio" name="userState" value="1" title="锁定">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">过期时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="userExpiredDate" id="userExpiredDate" placeholder="请选择过期日期,空表示永不过期" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remarks" placeholder="请输入备注" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2 layui-col-sm4 layui-col-xs12">
|
||||
<div class="layui-form-item" style="text-align: center;">
|
||||
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
|
||||
<input type="hidden" id="userAvatar" name="userAvatar">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-layout-admin">
|
||||
|
Loading…
Reference in New Issue
Block a user