parent
179062e6e5
commit
6704db8108
@ -0,0 +1,135 @@
|
|||||||
|
package com.ruoyi.system.api.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Set;
|
||||||
|
import com.ruoyi.system.api.domain.SysUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class LoginUser implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户唯一标识
|
||||||
|
*/
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名id
|
||||||
|
*/
|
||||||
|
private Long userid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆时间
|
||||||
|
*/
|
||||||
|
private Long loginTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间
|
||||||
|
*/
|
||||||
|
private Long expireTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限列表
|
||||||
|
*/
|
||||||
|
private Set<String> permissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色列表
|
||||||
|
*/
|
||||||
|
private Set<String> roles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
private SysUser sysUser;
|
||||||
|
|
||||||
|
public String getToken()
|
||||||
|
{
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token)
|
||||||
|
{
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserid()
|
||||||
|
{
|
||||||
|
return userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserid(Long userid)
|
||||||
|
{
|
||||||
|
this.userid = userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername()
|
||||||
|
{
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username)
|
||||||
|
{
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLoginTime()
|
||||||
|
{
|
||||||
|
return loginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginTime(Long loginTime)
|
||||||
|
{
|
||||||
|
this.loginTime = loginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getExpireTime()
|
||||||
|
{
|
||||||
|
return expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpireTime(Long expireTime)
|
||||||
|
{
|
||||||
|
this.expireTime = expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getPermissions()
|
||||||
|
{
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissions(Set<String> permissions)
|
||||||
|
{
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getRoles()
|
||||||
|
{
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(Set<String> roles)
|
||||||
|
{
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SysUser getSysUser()
|
||||||
|
{
|
||||||
|
return sysUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSysUser(SysUser sysUser)
|
||||||
|
{
|
||||||
|
this.sysUser = sysUser;
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
package com.ruoyi.system.api.model;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Set;
|
|
||||||
import com.ruoyi.system.api.domain.SysUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class UserInfo implements Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户基本信息
|
|
||||||
*/
|
|
||||||
private SysUser sysUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限标识集合
|
|
||||||
*/
|
|
||||||
private Set<String> permissions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色集合
|
|
||||||
*/
|
|
||||||
private Set<String> roles;
|
|
||||||
|
|
||||||
public SysUser getSysUser()
|
|
||||||
{
|
|
||||||
return sysUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSysUser(SysUser sysUser)
|
|
||||||
{
|
|
||||||
this.sysUser = sysUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getPermissions()
|
|
||||||
{
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPermissions(Set<String> permissions)
|
|
||||||
{
|
|
||||||
this.permissions = permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getRoles()
|
|
||||||
{
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoles(Set<String> roles)
|
|
||||||
{
|
|
||||||
this.roles = roles;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package com.ruoyi.auth.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Security 安全认证相关配置
|
|
||||||
* Oauth2依赖于Security 默认情况下WebSecurityConfig执行比ResourceServerConfig优先
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Order(99)
|
|
||||||
@Configuration
|
|
||||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private UserDetailsService userDetailsService;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder()
|
|
||||||
{
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Override
|
|
||||||
public AuthenticationManager authenticationManagerBean() throws Exception
|
|
||||||
{
|
|
||||||
return super.authenticationManagerBean();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception
|
|
||||||
{
|
|
||||||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception
|
|
||||||
{
|
|
||||||
http
|
|
||||||
.authorizeRequests()
|
|
||||||
.antMatchers(
|
|
||||||
"/actuator/**",
|
|
||||||
"/oauth/*",
|
|
||||||
"/token/**").permitAll()
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
.and().csrf().disable();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package com.ruoyi.auth.controller;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 身份信息获取
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/oauth")
|
|
||||||
public class UserController
|
|
||||||
{
|
|
||||||
@RequestMapping("/user")
|
|
||||||
public Principal user(Principal user)
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package com.ruoyi.auth.exception;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* oauth2自定义异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
@JsonSerialize(using = CustomOauthExceptionSerializer.class)
|
|
||||||
public class CustomOauthException extends OAuth2Exception
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public CustomOauthException(String msg)
|
|
||||||
{
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package com.ruoyi.auth.exception;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
|
||||||
import com.ruoyi.common.core.constant.HttpStatus;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义异常返回
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(CustomOauthExceptionSerializer.class);
|
|
||||||
|
|
||||||
public static final String BAD_CREDENTIALS = "Bad credentials";
|
|
||||||
|
|
||||||
public CustomOauthExceptionSerializer()
|
|
||||||
{
|
|
||||||
super(CustomOauthException.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serialize(CustomOauthException e, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
jsonGenerator.writeStartObject();
|
|
||||||
jsonGenerator.writeNumberField(AjaxResult.CODE_TAG, HttpStatus.ERROR);
|
|
||||||
if (StringUtils.equals(e.getMessage(), BAD_CREDENTIALS))
|
|
||||||
{
|
|
||||||
jsonGenerator.writeStringField(AjaxResult.MSG_TAG, "用户名或密码错误");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.warn("oauth2 认证异常 {} ", e);
|
|
||||||
jsonGenerator.writeStringField(AjaxResult.MSG_TAG, e.getMessage());
|
|
||||||
}
|
|
||||||
jsonGenerator.writeEndObject();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package com.ruoyi.auth.exception;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
|
||||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OAuth2 自定义异常处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception>
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public ResponseEntity<OAuth2Exception> translate(Exception e)
|
|
||||||
{
|
|
||||||
return ResponseEntity.status(HttpStatus.OK).body(new CustomOauthException(e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.ruoyi.auth.form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录对象
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class LoginBody
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 唯一标识
|
||||||
|
*/
|
||||||
|
private String uuid = "";
|
||||||
|
|
||||||
|
public String getUsername()
|
||||||
|
{
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username)
|
||||||
|
{
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword()
|
||||||
|
{
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password)
|
||||||
|
{
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid()
|
||||||
|
{
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid)
|
||||||
|
{
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
package com.ruoyi.auth.handler;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.ApplicationListener;
|
|
||||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.ruoyi.common.core.constant.Constants;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.security.domain.LoginUser;
|
|
||||||
import com.ruoyi.system.api.RemoteLogService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证成功处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class AuthenticationSuccessEventHandler implements ApplicationListener<AuthenticationSuccessEvent>
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private RemoteLogService remoteLogService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onApplicationEvent(AuthenticationSuccessEvent event)
|
|
||||||
{
|
|
||||||
Authentication authentication = (Authentication) event.getSource();
|
|
||||||
if (StringUtils.isNotEmpty(authentication.getAuthorities())
|
|
||||||
&& authentication.getPrincipal() instanceof LoginUser)
|
|
||||||
{
|
|
||||||
LoginUser user = (LoginUser) authentication.getPrincipal();
|
|
||||||
|
|
||||||
String username = user.getUsername();
|
|
||||||
|
|
||||||
// 记录用户登录日志
|
|
||||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.ruoyi.auth.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import com.ruoyi.common.core.constant.Constants;
|
||||||
|
import com.ruoyi.common.core.constant.UserConstants;
|
||||||
|
import com.ruoyi.common.core.domain.R;
|
||||||
|
import com.ruoyi.common.core.enums.UserStatus;
|
||||||
|
import com.ruoyi.common.core.exception.BaseException;
|
||||||
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
|
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.system.api.RemoteLogService;
|
||||||
|
import com.ruoyi.system.api.RemoteUserService;
|
||||||
|
import com.ruoyi.system.api.domain.SysUser;
|
||||||
|
import com.ruoyi.system.api.model.LoginUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录校验方法
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SysLoginService
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private RemoteLogService remoteLogService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RemoteUserService remoteUserService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
public LoginUser login(String username, String password)
|
||||||
|
{
|
||||||
|
// 用户名或密码为空 错误
|
||||||
|
if (StringUtils.isAnyBlank(username, password))
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
|
||||||
|
throw new BaseException("用户/密码必须填写");
|
||||||
|
}
|
||||||
|
// 密码如果不在指定范围内 错误
|
||||||
|
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||||
|
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
|
||||||
|
throw new BaseException("用户密码不在指定范围");
|
||||||
|
}
|
||||||
|
// 用户名不在指定范围内 错误
|
||||||
|
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|
||||||
|
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
|
||||||
|
throw new BaseException("用户名不在指定范围");
|
||||||
|
}
|
||||||
|
// 查询用户信息
|
||||||
|
R<LoginUser> userResult = remoteUserService.getUserInfo(username);
|
||||||
|
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
|
||||||
|
throw new BaseException("登录用户:" + username + " 不存在");
|
||||||
|
}
|
||||||
|
LoginUser userInfo = userResult.getData();
|
||||||
|
SysUser user = userResult.getData().getSysUser();
|
||||||
|
if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除");
|
||||||
|
|
||||||
|
throw new BaseException("对不起,您的账号:" + username + " 已被删除");
|
||||||
|
}
|
||||||
|
if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员");
|
||||||
|
throw new BaseException("对不起,您的账号:" + username + " 已停用");
|
||||||
|
}
|
||||||
|
if (!SecurityUtils.matchesPassword(password, user.getPassword()))
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码错误");
|
||||||
|
throw new BaseException("用户不存在/密码错误");
|
||||||
|
}
|
||||||
|
remoteLogService.saveLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout(String loginName)
|
||||||
|
{
|
||||||
|
remoteLogService.saveLogininfor(loginName, Constants.LOGOUT, "退出成功");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.common.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限异常
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class PreAuthorizeException extends RuntimeException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public PreAuthorizeException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -1,42 +0,0 @@
|
|||||||
package com.ruoyi.common.datascope.service;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import com.ruoyi.common.core.domain.R;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
|
||||||
import com.ruoyi.system.api.RemoteUserService;
|
|
||||||
import com.ruoyi.system.api.model.UserInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步调用用户服务
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class AwaitUserService
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AwaitUserService.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询当前用户信息
|
|
||||||
*
|
|
||||||
* @return 用户基本信息
|
|
||||||
*/
|
|
||||||
public UserInfo info()
|
|
||||||
{
|
|
||||||
String username = SecurityUtils.getUsername();
|
|
||||||
R<UserInfo> userResult = remoteUserService.getUserInfo(username);
|
|
||||||
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
|
|
||||||
{
|
|
||||||
log.info("数据权限范围查询用户:{} 不存在.", username);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return userResult.getData();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
com.ruoyi.common.datascope.service.AwaitUserService,\
|
|
||||||
com.ruoyi.common.datascope.aspect.DataScopeAspect
|
com.ruoyi.common.datascope.aspect.DataScopeAspect
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package com.ruoyi.common.security.config;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.beans.factory.annotation.Configurable;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 忽略服务间的认证
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
@Component
|
|
||||||
@Configurable
|
|
||||||
@ConfigurationProperties(prefix = "security.oauth2.ignore")
|
|
||||||
public class AuthIgnoreConfig
|
|
||||||
{
|
|
||||||
private List<String> urls = new ArrayList<>();
|
|
||||||
|
|
||||||
public List<String> getUrls()
|
|
||||||
{
|
|
||||||
return urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrls(List<String> urls)
|
|
||||||
{
|
|
||||||
this.urls = urls;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package com.ruoyi.common.security.config;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
|
||||||
import com.ruoyi.common.core.text.Convert;
|
|
||||||
import com.ruoyi.common.security.domain.LoginUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://my.oschina.net/giegie/blog/3023768 根据checktoken 的结果转化用户信息
|
|
||||||
*
|
|
||||||
* @author lengleng
|
|
||||||
*/
|
|
||||||
public class CommonUserConverter implements UserAuthenticationConverter
|
|
||||||
{
|
|
||||||
private static final String N_A = "N/A";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将授权信息返回到资源服务
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Map<String, ?> convertUserAuthentication(Authentication userAuthentication)
|
|
||||||
{
|
|
||||||
Map<String, Object> authMap = new LinkedHashMap<>();
|
|
||||||
authMap.put(USERNAME, userAuthentication.getName());
|
|
||||||
if (userAuthentication.getAuthorities() != null && !userAuthentication.getAuthorities().isEmpty())
|
|
||||||
{
|
|
||||||
authMap.put(AUTHORITIES, AuthorityUtils.authorityListToSet(userAuthentication.getAuthorities()));
|
|
||||||
}
|
|
||||||
return authMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户认证信息
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Authentication extractAuthentication(Map<String, ?> map)
|
|
||||||
{
|
|
||||||
if (map.containsKey(USERNAME))
|
|
||||||
{
|
|
||||||
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
|
|
||||||
|
|
||||||
Long userId = Convert.toLong(map.get(SecurityConstants.DETAILS_USER_ID));
|
|
||||||
String username = (String) map.get(SecurityConstants.DETAILS_USERNAME);
|
|
||||||
LoginUser user = new LoginUser(userId, username, N_A, true, true, true, true, authorities);
|
|
||||||
return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取权限资源信息
|
|
||||||
*/
|
|
||||||
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map)
|
|
||||||
{
|
|
||||||
Object authorities = map.get(AUTHORITIES);
|
|
||||||
if (authorities instanceof String)
|
|
||||||
{
|
|
||||||
return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
|
|
||||||
}
|
|
||||||
if (authorities instanceof Collection)
|
|
||||||
{
|
|
||||||
return AuthorityUtils.commaSeparatedStringToAuthorityList(
|
|
||||||
StringUtils.collectionToCommaDelimitedString((Collection<?>) authorities));
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Authorities must be either a String or a Collection");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package com.ruoyi.common.security.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @EnableGlobalMethodSecurity(securedEnabled=true)
|
|
||||||
* 开启@Secured 注解过滤权限
|
|
||||||
*
|
|
||||||
* @EnableGlobalMethodSecurity(jsr250Enabled=true)
|
|
||||||
* 开启@RolesAllowed 注解过滤权限
|
|
||||||
*
|
|
||||||
* @EnableGlobalMethodSecurity(prePostEnabled=true)
|
|
||||||
* 使用表达式时间方法级别的安全性 4个注解可用
|
|
||||||
* -@PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
|
|
||||||
* -@PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
|
|
||||||
* -@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
|
|
||||||
* -@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
|
||||||
public class MethodSecurityConfig
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package com.ruoyi.common.security.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
|
|
||||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
|
||||||
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
|
|
||||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
|
||||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
|
||||||
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
|
|
||||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* oauth2 服务配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableResourceServer
|
|
||||||
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private ResourceServerProperties resourceServerProperties;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private OAuth2ClientProperties oAuth2ClientProperties;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthIgnoreConfig authIgnoreConfig()
|
|
||||||
{
|
|
||||||
return new AuthIgnoreConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@LoadBalanced
|
|
||||||
public RestTemplate restTemplate()
|
|
||||||
{
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
|
|
||||||
return restTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ResourceServerTokenServices tokenServices()
|
|
||||||
{
|
|
||||||
RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
|
|
||||||
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
|
|
||||||
UserAuthenticationConverter userTokenConverter = new CommonUserConverter();
|
|
||||||
accessTokenConverter.setUserTokenConverter(userTokenConverter);
|
|
||||||
remoteTokenServices.setCheckTokenEndpointUrl(resourceServerProperties.getTokenInfoUri());
|
|
||||||
remoteTokenServices.setClientId(oAuth2ClientProperties.getClientId());
|
|
||||||
remoteTokenServices.setClientSecret(oAuth2ClientProperties.getClientSecret());
|
|
||||||
remoteTokenServices.setRestTemplate(restTemplate());
|
|
||||||
remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
|
|
||||||
return remoteTokenServices;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(HttpSecurity http) throws Exception
|
|
||||||
{
|
|
||||||
http.csrf().disable();
|
|
||||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
|
|
||||||
.authorizeRequests();
|
|
||||||
// 不登录可以访问
|
|
||||||
authIgnoreConfig().getUrls().forEach(url -> registry.antMatchers(url).permitAll());
|
|
||||||
registry.anyRequest().authenticated();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(ResourceServerSecurityConfigurer resources)
|
|
||||||
{
|
|
||||||
resources.tokenServices(tokenServices());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package com.ruoyi.common.security.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|
||||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入 SecurityImportBeanDefinitionRegistrar 自动加载类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class SecurityImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)
|
|
||||||
{
|
|
||||||
Class<ResourceServerConfig> aClass = ResourceServerConfig.class;
|
|
||||||
String beanName = StringUtils.uncapitalize(aClass.getSimpleName());
|
|
||||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ResourceServerConfig.class);
|
|
||||||
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package com.ruoyi.common.security.domain;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.User;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录用户身份权限
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class LoginUser extends User
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户ID
|
|
||||||
*/
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
public LoginUser(Long userId, String username, String password, boolean enabled, boolean accountNonExpired,
|
|
||||||
boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)
|
|
||||||
{
|
|
||||||
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getUserId()
|
|
||||||
{
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(Long userId)
|
|
||||||
{
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package com.ruoyi.common.security.feign;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import feign.RequestInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feign配置注册
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
@Configuration
|
|
||||||
public class OAuth2FeignConfig
|
|
||||||
{
|
|
||||||
@Bean
|
|
||||||
public RequestInterceptor requestInterceptor()
|
|
||||||
{
|
|
||||||
return new OAuth2FeignRequestInterceptor();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package com.ruoyi.common.security.feign;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
|
||||||
import feign.RequestInterceptor;
|
|
||||||
import feign.RequestTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* feign 请求拦截器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class OAuth2FeignRequestInterceptor implements RequestInterceptor
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void apply(RequestTemplate requestTemplate)
|
|
||||||
{
|
|
||||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
|
||||||
Authentication authentication = securityContext.getAuthentication();
|
|
||||||
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails)
|
|
||||||
{
|
|
||||||
OAuth2AuthenticationDetails dateils = (OAuth2AuthenticationDetails) authentication.getDetails();
|
|
||||||
requestTemplate.header(HttpHeaders.AUTHORIZATION,
|
|
||||||
String.format("%s %s", SecurityConstants.BEARER_TOKEN_TYPE, dateils.getTokenValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package com.ruoyi.common.security.handler;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
|
||||||
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.core.constant.HttpStatus;
|
|
||||||
import com.ruoyi.common.core.domain.R;
|
|
||||||
import com.ruoyi.common.core.utils.ServletUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义访问无权限资源时的异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class CustomAccessDeniedHandler extends OAuth2AccessDeniedHandler
|
|
||||||
{
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException)
|
|
||||||
{
|
|
||||||
logger.info("权限不足,请联系管理员 {}", request.getRequestURI());
|
|
||||||
|
|
||||||
String msg = authException.getMessage();
|
|
||||||
ServletUtils.renderString(response, JSON.toJSONString(R.fail(HttpStatus.FORBIDDEN, msg)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package com.ruoyi.common.security.service;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
|
||||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
|
||||||
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
|
|
||||||
import com.ruoyi.common.core.constant.CacheConstants;
|
|
||||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重写原生方法支持redis缓存
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class RedisClientDetailsService extends JdbcClientDetailsService
|
|
||||||
{
|
|
||||||
public RedisClientDetailsService(DataSource dataSource)
|
|
||||||
{
|
|
||||||
super(dataSource);
|
|
||||||
super.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
|
|
||||||
super.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Cacheable(value = CacheConstants.CLIENT_DETAILS_KEY, key = "#clientId", unless = "#result == null")
|
|
||||||
public ClientDetails loadClientByClientId(String clientId)
|
|
||||||
{
|
|
||||||
return super.loadClientByClientId(clientId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,123 @@
|
|||||||
|
package com.ruoyi.common.security.service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import com.ruoyi.common.core.constant.CacheConstants;
|
||||||
|
import com.ruoyi.common.core.constant.Constants;
|
||||||
|
import com.ruoyi.common.core.utils.IdUtils;
|
||||||
|
import com.ruoyi.common.core.utils.ServletUtils;
|
||||||
|
import com.ruoyi.common.redis.service.RedisService;
|
||||||
|
import com.ruoyi.system.api.model.LoginUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token验证处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TokenService
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
|
||||||
|
|
||||||
|
private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;
|
||||||
|
|
||||||
|
protected static final long MILLIS_SECOND = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建令牌
|
||||||
|
*/
|
||||||
|
public Map<String, Object> createToken(LoginUser loginUser)
|
||||||
|
{
|
||||||
|
// 生成token
|
||||||
|
String token = IdUtils.fastUUID();
|
||||||
|
loginUser.setToken(token);
|
||||||
|
loginUser.setUserid(loginUser.getSysUser().getUserId());
|
||||||
|
loginUser.setUsername(loginUser.getSysUser().getUserName());
|
||||||
|
refreshToken(loginUser);
|
||||||
|
|
||||||
|
// 保存或更新用户token
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("access_token", token);
|
||||||
|
map.put("expires_in", EXPIRE_TIME);
|
||||||
|
redisService.setCacheObject(ACCESS_TOKEN + token, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户身份信息
|
||||||
|
*
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
|
public LoginUser getLoginUser()
|
||||||
|
{
|
||||||
|
return getLoginUser(ServletUtils.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户身份信息
|
||||||
|
*
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
|
public LoginUser getLoginUser(HttpServletRequest request)
|
||||||
|
{
|
||||||
|
// 获取请求携带的令牌
|
||||||
|
String token = getToken(request);
|
||||||
|
if (StringUtils.isNotEmpty(token))
|
||||||
|
{
|
||||||
|
String userKey = getTokenKey(token);
|
||||||
|
LoginUser user = redisService.getCacheObject(userKey);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delLoginUser(String token)
|
||||||
|
{
|
||||||
|
if (StringUtils.isNotEmpty(token))
|
||||||
|
{
|
||||||
|
String userKey = getTokenKey(token);
|
||||||
|
redisService.deleteObject(userKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新令牌有效期
|
||||||
|
*
|
||||||
|
* @param loginUser 登录信息
|
||||||
|
*/
|
||||||
|
public Long refreshToken(LoginUser loginUser)
|
||||||
|
{
|
||||||
|
loginUser.setLoginTime(System.currentTimeMillis());
|
||||||
|
loginUser.setExpireTime(loginUser.getLoginTime() + EXPIRE_TIME * MILLIS_SECOND);
|
||||||
|
// 根据uuid将loginUser缓存
|
||||||
|
String userKey = getTokenKey(loginUser.getToken());
|
||||||
|
redisService.setCacheObject(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
|
||||||
|
return EXPIRE_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTokenKey(String token)
|
||||||
|
{
|
||||||
|
return ACCESS_TOKEN + token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求token
|
||||||
|
*/
|
||||||
|
private String getToken(HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String token = request.getHeader(CacheConstants.HEADER);
|
||||||
|
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||||
|
{
|
||||||
|
token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
package com.ruoyi.common.security.service;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
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.authority.AuthorityUtils;
|
|
||||||
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 com.ruoyi.common.core.domain.R;
|
|
||||||
import com.ruoyi.common.core.enums.UserStatus;
|
|
||||||
import com.ruoyi.common.core.exception.BaseException;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.security.domain.LoginUser;
|
|
||||||
import com.ruoyi.system.api.RemoteUserService;
|
|
||||||
import com.ruoyi.system.api.domain.SysUser;
|
|
||||||
import com.ruoyi.system.api.model.UserInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class UserDetailsServiceImpl implements UserDetailsService
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserDetails loadUserByUsername(String username)
|
|
||||||
{
|
|
||||||
R<UserInfo> userResult = remoteUserService.getUserInfo(username);
|
|
||||||
checkUser(userResult, username);
|
|
||||||
return getUserDetails(userResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkUser(R<UserInfo> userResult, String username)
|
|
||||||
{
|
|
||||||
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
|
|
||||||
{
|
|
||||||
log.info("登录用户:{} 不存在.", username);
|
|
||||||
throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
|
|
||||||
}
|
|
||||||
else if (UserStatus.DELETED.getCode().equals(userResult.getData().getSysUser().getDelFlag()))
|
|
||||||
{
|
|
||||||
log.info("登录用户:{} 已被删除.", username);
|
|
||||||
throw new BaseException("对不起,您的账号:" + username + " 已被删除");
|
|
||||||
}
|
|
||||||
else if (UserStatus.DISABLE.getCode().equals(userResult.getData().getSysUser().getStatus()))
|
|
||||||
{
|
|
||||||
log.info("登录用户:{} 已被停用.", username);
|
|
||||||
throw new BaseException("对不起,您的账号:" + username + " 已停用");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserDetails getUserDetails(R<UserInfo> result)
|
|
||||||
{
|
|
||||||
UserInfo info = result.getData();
|
|
||||||
Set<String> dbAuthsSet = new HashSet<String>();
|
|
||||||
if (StringUtils.isNotEmpty(info.getRoles()))
|
|
||||||
{
|
|
||||||
// 获取角色
|
|
||||||
dbAuthsSet.addAll(info.getRoles());
|
|
||||||
// 获取权限
|
|
||||||
dbAuthsSet.addAll(info.getPermissions());
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> authorities = AuthorityUtils
|
|
||||||
.createAuthorityList(dbAuthsSet.toArray(new String[0]));
|
|
||||||
SysUser user = info.getSysUser();
|
|
||||||
|
|
||||||
return new LoginUser(user.getUserId(), user.getUserName(), user.getPassword(), true, true, true, true,
|
|
||||||
authorities);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.ruoyi.gateway.filter;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
|
||||||
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
|
||||||
|
{
|
||||||
|
public CacheRequestFilter()
|
||||||
|
{
|
||||||
|
super(Config.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name()
|
||||||
|
{
|
||||||
|
return "CacheRequestFilter";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GatewayFilter apply(Config config)
|
||||||
|
{
|
||||||
|
CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
|
||||||
|
Integer order = config.getOrder();
|
||||||
|
if (order == null)
|
||||||
|
{
|
||||||
|
return cacheRequestGatewayFilter;
|
||||||
|
}
|
||||||
|
return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CacheRequestGatewayFilter implements GatewayFilter
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||||
|
{
|
||||||
|
// GET DELETE 不过滤
|
||||||
|
HttpMethod method = exchange.getRequest().getMethod();
|
||||||
|
if (method == null || method.matches("GET") || method.matches("DELETE"))
|
||||||
|
{
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
|
||||||
|
byte[] bytes = new byte[dataBuffer.readableByteCount()];
|
||||||
|
dataBuffer.read(bytes);
|
||||||
|
DataBufferUtils.release(dataBuffer);
|
||||||
|
return bytes;
|
||||||
|
}).defaultIfEmpty(new byte[0]).flatMap(bytes -> {
|
||||||
|
DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
|
||||||
|
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest())
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody()
|
||||||
|
{
|
||||||
|
if (bytes.length > 0)
|
||||||
|
{
|
||||||
|
return Flux.just(dataBufferFactory.wrap(bytes));
|
||||||
|
}
|
||||||
|
return Flux.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return chain.filter(exchange.mutate().request(decorator).build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> shortcutFieldOrder()
|
||||||
|
{
|
||||||
|
return Collections.singletonList("order");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Config
|
||||||
|
{
|
||||||
|
private Integer order;
|
||||||
|
|
||||||
|
public Integer getOrder()
|
||||||
|
{
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrder(Integer order)
|
||||||
|
{
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,94 +0,0 @@
|
|||||||
package com.ruoyi.system.controller;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.core.web.controller.BaseController;
|
|
||||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
|
||||||
import com.ruoyi.common.core.web.page.TableDataInfo;
|
|
||||||
import com.ruoyi.common.log.annotation.Log;
|
|
||||||
import com.ruoyi.common.log.enums.BusinessType;
|
|
||||||
import com.ruoyi.system.domain.SysClientDetails;
|
|
||||||
import com.ruoyi.system.service.ISysClientDetailsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端配置 信息操作处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/client")
|
|
||||||
public class SysClientDetailsController extends BaseController
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private ISysClientDetailsService sysClientDetailsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询终端配置列表
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('system:client:list')")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo list(SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
startPage();
|
|
||||||
List<SysClientDetails> list = sysClientDetailsService.selectSysClientDetailsList(sysClientDetails);
|
|
||||||
return getDataTable(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取终端配置详细信息
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('system:client:query')")
|
|
||||||
@GetMapping(value = "/{clientId}")
|
|
||||||
public AjaxResult getInfo(@PathVariable("clientId") String clientId)
|
|
||||||
{
|
|
||||||
return AjaxResult.success(sysClientDetailsService.selectSysClientDetailsById(clientId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增终端配置
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('system:client:add')")
|
|
||||||
@Log(title = "终端配置", businessType = BusinessType.INSERT)
|
|
||||||
@PostMapping
|
|
||||||
public AjaxResult add(@RequestBody SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
String clientId = sysClientDetails.getClientId();
|
|
||||||
if (StringUtils.isNotNull(sysClientDetailsService.selectSysClientDetailsById(clientId)))
|
|
||||||
{
|
|
||||||
return AjaxResult.error("新增终端'" + clientId + "'失败,编号已存在");
|
|
||||||
}
|
|
||||||
return toAjax(sysClientDetailsService.insertSysClientDetails(sysClientDetails));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改终端配置
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('system:client:edit')")
|
|
||||||
@Log(title = "终端配置", businessType = BusinessType.UPDATE)
|
|
||||||
@PutMapping
|
|
||||||
public AjaxResult edit(@RequestBody SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
return toAjax(sysClientDetailsService.updateSysClientDetails(sysClientDetails));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除终端配置
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('system:client:remove')")
|
|
||||||
@Log(title = "终端配置", businessType = BusinessType.DELETE)
|
|
||||||
@DeleteMapping("/{clientIds}")
|
|
||||||
public AjaxResult remove(@PathVariable String[] clientIds)
|
|
||||||
{
|
|
||||||
return toAjax(sysClientDetailsService.deleteSysClientDetailsByIds(clientIds));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package com.ruoyi.system.mapper;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import com.ruoyi.system.domain.SysClientDetails;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端配置Mapper接口
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public interface SysClientDetailsMapper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 查询终端配置
|
|
||||||
*
|
|
||||||
* @param clientId 终端配置ID
|
|
||||||
* @return 终端配置
|
|
||||||
*/
|
|
||||||
public SysClientDetails selectSysClientDetailsById(String clientId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询终端配置列表
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 终端配置集合
|
|
||||||
*/
|
|
||||||
public List<SysClientDetails> selectSysClientDetailsList(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int insertSysClientDetails(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int updateSysClientDetails(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除终端配置
|
|
||||||
*
|
|
||||||
* @param clientId 终端配置ID
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int deleteSysClientDetailsById(String clientId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除终端配置
|
|
||||||
*
|
|
||||||
* @param clientIds 需要删除的数据ID
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int deleteSysClientDetailsByIds(String[] clientIds);
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package com.ruoyi.system.service;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import com.ruoyi.system.domain.SysClientDetails;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端配置Service接口
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public interface ISysClientDetailsService
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 查询终端配置
|
|
||||||
*
|
|
||||||
* @param clientId 终端配置ID
|
|
||||||
* @return 终端配置
|
|
||||||
*/
|
|
||||||
public SysClientDetails selectSysClientDetailsById(String clientId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询终端配置列表
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 终端配置集合
|
|
||||||
*/
|
|
||||||
public List<SysClientDetails> selectSysClientDetailsList(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int insertSysClientDetails(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int updateSysClientDetails(SysClientDetails sysClientDetails);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除终端配置
|
|
||||||
*
|
|
||||||
* @param clientIds 需要删除的终端配置ID
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int deleteSysClientDetailsByIds(String[] clientIds);
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package com.ruoyi.system.service.impl;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import com.ruoyi.common.core.constant.CacheConstants;
|
|
||||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
|
||||||
import com.ruoyi.system.domain.SysClientDetails;
|
|
||||||
import com.ruoyi.system.mapper.SysClientDetailsMapper;
|
|
||||||
import com.ruoyi.system.service.ISysClientDetailsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端配置Service业务层处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class SysClientDetailsServiceImpl implements ISysClientDetailsService
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private SysClientDetailsMapper sysClientDetailsMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询终端配置
|
|
||||||
*
|
|
||||||
* @param clientId 终端配置ID
|
|
||||||
* @return 终端配置
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public SysClientDetails selectSysClientDetailsById(String clientId)
|
|
||||||
{
|
|
||||||
return sysClientDetailsMapper.selectSysClientDetailsById(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询终端配置列表
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 终端配置
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<SysClientDetails> selectSysClientDetailsList(SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
return sysClientDetailsMapper.selectSysClientDetailsList(sysClientDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int insertSysClientDetails(SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
sysClientDetails.setClientSecret(SecurityUtils.encryptPassword(sysClientDetails.getOriginSecret()));
|
|
||||||
return sysClientDetailsMapper.insertSysClientDetails(sysClientDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改终端配置
|
|
||||||
*
|
|
||||||
* @param sysClientDetails 终端配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@CacheEvict(value = CacheConstants.CLIENT_DETAILS_KEY, key = "#sysClientDetails.clientId")
|
|
||||||
public int updateSysClientDetails(SysClientDetails sysClientDetails)
|
|
||||||
{
|
|
||||||
sysClientDetails.setClientSecret(SecurityUtils.encryptPassword(sysClientDetails.getOriginSecret()));
|
|
||||||
return sysClientDetailsMapper.updateSysClientDetails(sysClientDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除终端配置
|
|
||||||
*
|
|
||||||
* @param clientIds 需要删除的终端配置ID
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@CacheEvict(value = CacheConstants.CLIENT_DETAILS_KEY, allEntries = true)
|
|
||||||
public int deleteSysClientDetailsByIds(String[] clientIds)
|
|
||||||
{
|
|
||||||
return sysClientDetailsMapper.deleteSysClientDetailsByIds(clientIds);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE mapper
|
|
||||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="com.ruoyi.system.mapper.SysClientDetailsMapper">
|
|
||||||
|
|
||||||
<resultMap type="SysClientDetails" id="SysClientDetailsResult">
|
|
||||||
<result property="clientId" column="client_id" />
|
|
||||||
<result property="resourceIds" column="resource_ids" />
|
|
||||||
<result property="clientSecret" column="client_secret" />
|
|
||||||
<result property="scope" column="scope" />
|
|
||||||
<result property="authorizedGrantTypes" column="authorized_grant_types" />
|
|
||||||
<result property="webServerRedirectUri" column="web_server_redirect_uri" />
|
|
||||||
<result property="authorities" column="authorities" />
|
|
||||||
<result property="accessTokenValidity" column="access_token_validity" />
|
|
||||||
<result property="refreshTokenValidity" column="refresh_token_validity" />
|
|
||||||
<result property="additionalInformation" column="additional_information" />
|
|
||||||
<result property="autoapprove" column="autoapprove" />
|
|
||||||
<result property="originSecret" column="origin_secret" />
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<sql id="selectSysClientDetailsVo">
|
|
||||||
select client_id, resource_ids, client_secret, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove, origin_secret from sys_oauth_client_details
|
|
||||||
</sql>
|
|
||||||
|
|
||||||
<select id="selectSysClientDetailsList" parameterType="SysClientDetails" resultMap="SysClientDetailsResult">
|
|
||||||
<include refid="selectSysClientDetailsVo"/>
|
|
||||||
<where>
|
|
||||||
<if test="clientId != null and clientId != ''"> and client_id = #{clientId}</if>
|
|
||||||
</where>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="selectSysClientDetailsById" parameterType="String" resultMap="SysClientDetailsResult">
|
|
||||||
<include refid="selectSysClientDetailsVo"/>
|
|
||||||
where client_id = #{clientId}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<insert id="insertSysClientDetails" parameterType="SysClientDetails">
|
|
||||||
insert into sys_oauth_client_details
|
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
|
||||||
<if test="clientId != null">client_id,</if>
|
|
||||||
<if test="resourceIds != null">resource_ids,</if>
|
|
||||||
<if test="clientSecret != null">client_secret,</if>
|
|
||||||
<if test="scope != null">scope,</if>
|
|
||||||
<if test="authorizedGrantTypes != null">authorized_grant_types,</if>
|
|
||||||
<if test="webServerRedirectUri != null">web_server_redirect_uri,</if>
|
|
||||||
<if test="authorities != null">authorities,</if>
|
|
||||||
<if test="accessTokenValidity != null">access_token_validity,</if>
|
|
||||||
<if test="refreshTokenValidity != null">refresh_token_validity,</if>
|
|
||||||
<if test="additionalInformation != null">additional_information,</if>
|
|
||||||
<if test="autoapprove != null">autoapprove,</if>
|
|
||||||
<if test="originSecret != null">origin_secret,</if>
|
|
||||||
</trim>
|
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
|
||||||
<if test="clientId != null">#{clientId},</if>
|
|
||||||
<if test="resourceIds != null">#{resourceIds},</if>
|
|
||||||
<if test="clientSecret != null">#{clientSecret},</if>
|
|
||||||
<if test="scope != null">#{scope},</if>
|
|
||||||
<if test="authorizedGrantTypes != null">#{authorizedGrantTypes},</if>
|
|
||||||
<if test="webServerRedirectUri != null">#{webServerRedirectUri},</if>
|
|
||||||
<if test="authorities != null">#{authorities},</if>
|
|
||||||
<if test="accessTokenValidity != null">#{accessTokenValidity},</if>
|
|
||||||
<if test="refreshTokenValidity != null">#{refreshTokenValidity},</if>
|
|
||||||
<if test="additionalInformation != null">#{additionalInformation},</if>
|
|
||||||
<if test="autoapprove != null ">#{autoapprove},</if>
|
|
||||||
<if test="originSecret != null ">#{originSecret},</if>
|
|
||||||
</trim>
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<update id="updateSysClientDetails" parameterType="SysClientDetails">
|
|
||||||
update sys_oauth_client_details
|
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
|
||||||
<if test="resourceIds != null">resource_ids = #{resourceIds},</if>
|
|
||||||
<if test="clientSecret != null">client_secret = #{clientSecret},</if>
|
|
||||||
<if test="scope != null">scope = #{scope},</if>
|
|
||||||
<if test="authorizedGrantTypes != null">authorized_grant_types = #{authorizedGrantTypes},</if>
|
|
||||||
<if test="webServerRedirectUri != null">web_server_redirect_uri = #{webServerRedirectUri},</if>
|
|
||||||
<if test="authorities != null">authorities = #{authorities},</if>
|
|
||||||
<if test="accessTokenValidity != null">access_token_validity = #{accessTokenValidity},</if>
|
|
||||||
<if test="refreshTokenValidity != null">refresh_token_validity = #{refreshTokenValidity},</if>
|
|
||||||
<if test="additionalInformation != null">additional_information = #{additionalInformation},</if>
|
|
||||||
<if test="autoapprove != null">autoapprove = #{autoapprove},</if>
|
|
||||||
<if test="originSecret != null">origin_secret = #{originSecret},</if>
|
|
||||||
</trim>
|
|
||||||
where client_id = #{clientId}
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<delete id="deleteSysClientDetailsById" parameterType="String">
|
|
||||||
delete from sys_oauth_client_details where client_id = #{clientId}
|
|
||||||
</delete>
|
|
||||||
|
|
||||||
<delete id="deleteSysClientDetailsByIds" parameterType="String">
|
|
||||||
delete from sys_oauth_client_details where client_id in
|
|
||||||
<foreach item="clientId" collection="array" open="(" separator="," close=")">
|
|
||||||
#{clientId}
|
|
||||||
</foreach>
|
|
||||||
</delete>
|
|
||||||
|
|
||||||
</mapper>
|
|
@ -1,44 +0,0 @@
|
|||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
// 查询终端配置列表
|
|
||||||
export function listClient(query) {
|
|
||||||
return request({
|
|
||||||
url: '/system/client/list',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询终端配置详细
|
|
||||||
export function getClient(clientId) {
|
|
||||||
return request({
|
|
||||||
url: '/system/client/' + clientId,
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增终端配置
|
|
||||||
export function addClient(data) {
|
|
||||||
return request({
|
|
||||||
url: '/system/client',
|
|
||||||
method: 'post',
|
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改终端配置
|
|
||||||
export function updateClient(data) {
|
|
||||||
return request({
|
|
||||||
url: '/system/client',
|
|
||||||
method: 'put',
|
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除终端配置
|
|
||||||
export function delClient(clientId) {
|
|
||||||
return request({
|
|
||||||
url: '/system/client/' + clientId,
|
|
||||||
method: 'delete'
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,292 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="app-container">
|
|
||||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" @submit.native.prevent>
|
|
||||||
<el-form-item label="终端编号" prop="clientId">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.clientId"
|
|
||||||
placeholder="终端编号"
|
|
||||||
clearable
|
|
||||||
size="small"
|
|
||||||
@keyup.enter.native="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
||||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<el-row :gutter="10" class="mb8">
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
icon="el-icon-plus"
|
|
||||||
size="mini"
|
|
||||||
@click="handleAdd"
|
|
||||||
v-hasPermi="['system:client:add']"
|
|
||||||
>新增</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button
|
|
||||||
type="success"
|
|
||||||
icon="el-icon-edit"
|
|
||||||
size="mini"
|
|
||||||
:disabled="single"
|
|
||||||
@click="handleUpdate"
|
|
||||||
v-hasPermi="['system:client:edit']"
|
|
||||||
>修改</el-button>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
icon="el-icon-delete"
|
|
||||||
size="mini"
|
|
||||||
:disabled="multiple"
|
|
||||||
@click="handleDelete"
|
|
||||||
v-hasPermi="['system:client:remove']"
|
|
||||||
>删除</el-button>
|
|
||||||
</el-col>
|
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange">
|
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
|
||||||
<el-table-column label="编号" align="center" prop="clientId" />
|
|
||||||
<el-table-column label="安全码" align="center" prop="originSecret" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="授权范围" align="center" prop="scope" />
|
|
||||||
<el-table-column label="授权类型" align="center" prop="authorizedGrantTypes" :formatter="authorizedGrantTypesFormat" :show-overflow-tooltip="true"/>
|
|
||||||
<el-table-column label="令牌时效" align="center" prop="accessTokenValidity" />
|
|
||||||
<el-table-column label="刷新时效" align="center" prop="refreshTokenValidity" />
|
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button
|
|
||||||
size="mini"
|
|
||||||
type="text"
|
|
||||||
icon="el-icon-edit"
|
|
||||||
@click="handleUpdate(scope.row)"
|
|
||||||
v-hasPermi="['system:client:edit']"
|
|
||||||
>修改</el-button>
|
|
||||||
<el-button
|
|
||||||
size="mini"
|
|
||||||
type="text"
|
|
||||||
icon="el-icon-delete"
|
|
||||||
@click="handleDelete(scope.row)"
|
|
||||||
v-hasPermi="['system:client:remove']"
|
|
||||||
>删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<pagination
|
|
||||||
v-show="total>0"
|
|
||||||
:total="total"
|
|
||||||
:page.sync="queryParams.pageNum"
|
|
||||||
:limit.sync="queryParams.pageSize"
|
|
||||||
@pagination="getList"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 添加或修改终端对话框 -->
|
|
||||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
||||||
<el-form-item label="编号" prop="clientId">
|
|
||||||
<el-input v-model="form.clientId" placeholder="请输入编号" :disabled="!isAdd" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="安全码" prop="originSecret">
|
|
||||||
<el-input v-model="form.originSecret" placeholder="请输入安全码" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="授权范围" prop="scope">
|
|
||||||
<el-input v-model="form.scope" placeholder="请输入授权范围" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="授权类型" prop="authorizedGrantTypes">
|
|
||||||
<el-checkbox-group v-model="form.authorizedGrantTypes">
|
|
||||||
<el-checkbox
|
|
||||||
v-for="dict in authorizedGrantTypesOptions"
|
|
||||||
:key="dict.dictValue"
|
|
||||||
:label="dict.dictValue">
|
|
||||||
{{dict.dictLabel}}
|
|
||||||
</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="令牌时效" prop="accessTokenValidity">
|
|
||||||
<el-input-number v-model="form.accessTokenValidity" controls-position="right" :min="0" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="刷新时效" prop="refreshTokenValidity">
|
|
||||||
<el-input-number v-model="form.refreshTokenValidity" controls-position="right" :min="0" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer" class="dialog-footer">
|
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
||||||
<el-button @click="cancel">取 消</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { listClient, getClient, delClient, addClient, updateClient } from "@/api/system/client";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "Client",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
// 遮罩层
|
|
||||||
loading: true,
|
|
||||||
// 选中数组
|
|
||||||
ids: [],
|
|
||||||
// 非单个禁用
|
|
||||||
single: true,
|
|
||||||
// 非多个禁用
|
|
||||||
multiple: true,
|
|
||||||
// 显示搜索条件
|
|
||||||
showSearch: true,
|
|
||||||
// 总条数
|
|
||||||
total: 0,
|
|
||||||
// 终端表格数据
|
|
||||||
clientList: [],
|
|
||||||
// 弹出层标题
|
|
||||||
title: "",
|
|
||||||
// 是否显示弹出层
|
|
||||||
open: false,
|
|
||||||
// 终端授权类型字典
|
|
||||||
authorizedGrantTypesOptions: [],
|
|
||||||
// 查询参数
|
|
||||||
queryParams: {
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
clientId: undefined
|
|
||||||
},
|
|
||||||
// 是否新增
|
|
||||||
isAdd: false,
|
|
||||||
// 表单参数
|
|
||||||
form: {},
|
|
||||||
// 表单校验
|
|
||||||
rules: {
|
|
||||||
clientId: [
|
|
||||||
{ required: true, message: "编号不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
originSecret: [
|
|
||||||
{ required: true, message: "安全码不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
scope: [
|
|
||||||
{ required: true, message: "授权范围不能为空", trigger: "blur" }
|
|
||||||
],
|
|
||||||
authorizedGrantTypes: [
|
|
||||||
{ required: true, message: "授权类型不能为空", trigger: "blur" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getList();
|
|
||||||
this.getDicts("sys_grant_type").then(response => {
|
|
||||||
this.authorizedGrantTypesOptions = response.data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/** 查询终端列表 */
|
|
||||||
getList() {
|
|
||||||
this.loading = true;
|
|
||||||
listClient(this.queryParams).then(response => {
|
|
||||||
this.clientList = response.rows;
|
|
||||||
this.total = response.total;
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 终端授权类型字典翻译
|
|
||||||
authorizedGrantTypesFormat(row, column) {
|
|
||||||
return this.selectDictLabels(this.authorizedGrantTypesOptions, row.authorizedGrantTypes);
|
|
||||||
},
|
|
||||||
// 取消按钮
|
|
||||||
cancel() {
|
|
||||||
this.open = false;
|
|
||||||
this.reset();
|
|
||||||
},
|
|
||||||
// 表单重置
|
|
||||||
reset() {
|
|
||||||
this.form = {
|
|
||||||
clientId: undefined,
|
|
||||||
clientSecret: undefined,
|
|
||||||
scope: "server",
|
|
||||||
authorizedGrantTypes: [],
|
|
||||||
accessTokenValidity: 3600,
|
|
||||||
refreshTokenValidity: 7200
|
|
||||||
};
|
|
||||||
this.resetForm("form");
|
|
||||||
},
|
|
||||||
/** 搜索按钮操作 */
|
|
||||||
handleQuery() {
|
|
||||||
this.queryParams.pageNum = 1;
|
|
||||||
this.getList();
|
|
||||||
},
|
|
||||||
/** 重置按钮操作 */
|
|
||||||
resetQuery() {
|
|
||||||
this.resetForm("queryForm");
|
|
||||||
this.handleQuery();
|
|
||||||
},
|
|
||||||
// 多选框选中数据
|
|
||||||
handleSelectionChange(selection) {
|
|
||||||
this.ids = selection.map(item => item.clientId);
|
|
||||||
this.single = selection.length != 1;
|
|
||||||
this.multiple = !selection.length;
|
|
||||||
},
|
|
||||||
/** 新增按钮操作 */
|
|
||||||
handleAdd() {
|
|
||||||
this.reset();
|
|
||||||
this.open = true;
|
|
||||||
this.isAdd = true;
|
|
||||||
this.title = "添加终端";
|
|
||||||
},
|
|
||||||
/** 修改按钮操作 */
|
|
||||||
handleUpdate(row) {
|
|
||||||
this.reset();
|
|
||||||
this.isAdd = false;
|
|
||||||
const clientId = row.clientId || this.ids;
|
|
||||||
getClient(clientId).then(response => {
|
|
||||||
this.form = response.data;
|
|
||||||
this.form.authorizedGrantTypes = this.form.authorizedGrantTypes.split(",");
|
|
||||||
this.open = true;
|
|
||||||
this.title = "修改终端";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/** 提交按钮 */
|
|
||||||
submitForm: function() {
|
|
||||||
this.$refs["form"].validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
this.form.authorizedGrantTypes = this.form.authorizedGrantTypes.join(",");
|
|
||||||
if (!this.isAdd && this.form.clientId != undefined) {
|
|
||||||
updateClient(this.form).then(response => {
|
|
||||||
if (response.code === 200) {
|
|
||||||
this.msgSuccess("修改成功");
|
|
||||||
this.open = false;
|
|
||||||
this.getList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addClient(this.form).then(response => {
|
|
||||||
if (response.code === 200) {
|
|
||||||
this.msgSuccess("新增成功");
|
|
||||||
this.open = false;
|
|
||||||
this.getList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/** 删除按钮操作 */
|
|
||||||
handleDelete(row) {
|
|
||||||
const clientIds = row.clientId || this.ids;
|
|
||||||
this.$confirm('是否确认删除终端编号为"' + clientIds + '"的数据项?', "警告", {
|
|
||||||
confirmButtonText: "确定",
|
|
||||||
cancelButtonText: "取消",
|
|
||||||
type: "warning"
|
|
||||||
}).then(function() {
|
|
||||||
return delClient(clientIds);
|
|
||||||
}).then(() => {
|
|
||||||
this.getList();
|
|
||||||
this.msgSuccess("删除成功");
|
|
||||||
}).catch(function() {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
Loading…
Reference in new issue