sentinel
This commit is contained in:
parent
fff8fb7d86
commit
46eb9a0303
|
|
@ -22,6 +22,13 @@
|
|||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-security-core -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.ruoyi.system.api;
|
||||
|
||||
import com.ruoyi.system.api.model.RoleAndPermission;
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
|
@ -8,6 +10,8 @@ import com.ruoyi.common.core.domain.R;
|
|||
import com.ruoyi.system.api.factory.RemoteUserFallbackFactory;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户服务
|
||||
*
|
||||
|
|
@ -23,5 +27,34 @@ public interface RemoteUserService
|
|||
* @return 结果
|
||||
*/
|
||||
@GetMapping(value = "/user/info/{username}")
|
||||
public R<LoginUser> getUserInfo(@PathVariable("username") String username);
|
||||
public R<UserInfo> getUserInfo(@PathVariable("username") String username);
|
||||
|
||||
/**
|
||||
* 根据用户id查询角色
|
||||
*
|
||||
* @param userId 用户名
|
||||
* @return 结果
|
||||
*/
|
||||
@GetMapping(value = "/user/roles/{userId}")
|
||||
public R<Set<String>> getRoles(@PathVariable("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户id查询权限
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/user/permissions/{userId}")
|
||||
public R<Set<String>> getPermissions(@PathVariable("userId") Long userId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据用户id查询角色和权限
|
||||
*
|
||||
* @param userId 用户名
|
||||
* @return 结果
|
||||
*/
|
||||
@GetMapping(value = "/user/rolesAndPermissions/{userId}")
|
||||
public R<RoleAndPermission> getRolesAndPermissions(@PathVariable("userId") Long userId);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.ruoyi.system.api.factory;
|
||||
|
||||
import com.ruoyi.system.api.model.RoleAndPermission;
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
@ -8,6 +10,8 @@ import com.ruoyi.system.api.RemoteUserService;
|
|||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import feign.hystrix.FallbackFactory;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户服务降级处理
|
||||
*
|
||||
|
|
@ -25,10 +29,25 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
|
|||
return new RemoteUserService()
|
||||
{
|
||||
@Override
|
||||
public R<LoginUser> getUserInfo(String username)
|
||||
public R<UserInfo> getUserInfo(String username)
|
||||
{
|
||||
return R.fail("获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Set<String>> getRoles(Long userId) {
|
||||
return R.fail("获取用户角色失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Set<String>> getPermissions(Long userId) {
|
||||
return R.fail("获取用户权限失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<RoleAndPermission> getRolesAndPermissions(Long userId) {
|
||||
return R.fail("获取用户角色和权限失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,28 @@
|
|||
package com.ruoyi.system.api.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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 org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class LoginUser implements Serializable
|
||||
@Slf4j
|
||||
public class LoginUser implements Serializable, UserDetails,CredentialsContainer
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
@ -21,7 +34,7 @@ public class LoginUser implements Serializable
|
|||
/**
|
||||
* 用户名id
|
||||
*/
|
||||
private Long userid;
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
|
|
@ -58,6 +71,63 @@ public class LoginUser implements Serializable
|
|||
*/
|
||||
private SysUser sysUser;
|
||||
|
||||
private String password;
|
||||
|
||||
private Set<GrantedAuthority> authorities;
|
||||
|
||||
private boolean accountNonExpired;
|
||||
|
||||
private boolean accountNonLocked;
|
||||
|
||||
private boolean credentialsNonExpired;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
public LoginUser() {
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
}
|
||||
|
||||
public LoginUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
}
|
||||
|
||||
public LoginUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
this.enabled = enabled;
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
}
|
||||
|
||||
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
public LoginUser(Long userid, String username, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
this.enabled = enabled;
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
this.username = username;
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
this.userId = userid;
|
||||
}
|
||||
|
||||
public LoginUser(Long userid, String username,String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
this.enabled = enabled;
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
this.userId = userid;
|
||||
}
|
||||
|
||||
public String getToken()
|
||||
{
|
||||
return token;
|
||||
|
|
@ -68,16 +138,17 @@ public class LoginUser implements Serializable
|
|||
this.token = token;
|
||||
}
|
||||
|
||||
public Long getUserid()
|
||||
public Long getUserId()
|
||||
{
|
||||
return userid;
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserid(Long userid)
|
||||
public void setUserId(Long userId)
|
||||
{
|
||||
this.userid = userid;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
|
|
@ -147,4 +218,221 @@ public class LoginUser implements Serializable
|
|||
{
|
||||
this.sysUser = sysUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return this.authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.accountNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.accountNonLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.credentialsNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
this.password = null;
|
||||
}
|
||||
|
||||
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
||||
SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet(new LoginUser.AuthorityComparator());
|
||||
Iterator var2 = authorities.iterator();
|
||||
|
||||
while(var2.hasNext()) {
|
||||
GrantedAuthority grantedAuthority = (GrantedAuthority)var2.next();
|
||||
Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
|
||||
sortedAuthorities.add(grantedAuthority);
|
||||
}
|
||||
|
||||
return sortedAuthorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object rhs) {
|
||||
return rhs instanceof LoginUser ? this.username.equals(((LoginUser)rhs).username) : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.username.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public static LoginUser.UserBuilder withDefaultPasswordEncoder() {
|
||||
log.warn("User.withDefaultPasswordEncoder() is considered unsafe for production and is only intended for sample applications.");
|
||||
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
LoginUser.UserBuilder var10000 = builder();
|
||||
encoder.getClass();
|
||||
return var10000.passwordEncoder(encoder::encode);
|
||||
}
|
||||
|
||||
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) {
|
||||
Assert.notNull(username, "username cannot be null");
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder password(String password) {
|
||||
Assert.notNull(password, "password cannot be null");
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginUser.UserBuilder passwordEncoder(Function<String, String> encoder) {
|
||||
Assert.notNull(encoder, "encoder cannot be null");
|
||||
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];
|
||||
Assert.isTrue(!role.startsWith("ROLE_"), () -> {
|
||||
return role + " cannot start with ROLE_ (it is automatically added)";
|
||||
});
|
||||
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 = 530L;
|
||||
|
||||
private AuthorityComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(GrantedAuthority g1, GrantedAuthority g2) {
|
||||
if (g2.getAuthority() == null) {
|
||||
return -1;
|
||||
} else {
|
||||
return g1.getAuthority() == null ? 1 : g1.getAuthority().compareTo(g2.getAuthority());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
package com.ruoyi.system.api.model;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色表 sys_role
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class RoleAndPermission implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 角色集合
|
||||
*/
|
||||
private Set<String> roles ;
|
||||
|
||||
/**
|
||||
* 权限集合
|
||||
*/
|
||||
private Set<String> permissions ;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.ruoyi.system.api.model;
|
||||
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
package com.ruoyi.auth.config;
|
||||
|
||||
import com.ruoyi.auth.exception.CustomWebResponseExceptionTranslator;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.security.service.RedisClientDetailsService;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* OAuth2 认证服务配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAuthorizationServer
|
||||
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter
|
||||
{
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Autowired
|
||||
private RedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private TokenEnhancer tokenEnhancer;
|
||||
|
||||
/**
|
||||
* 定义授权和令牌端点以及令牌服务
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
|
||||
{
|
||||
endpoints
|
||||
// 请求方式
|
||||
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
|
||||
// 指定token存储位置
|
||||
.tokenStore(tokenStore())
|
||||
// 自定义生成令牌
|
||||
.tokenEnhancer(tokenEnhancer)
|
||||
// 用户账号密码认证
|
||||
.userDetailsService(userDetailsService)
|
||||
// 指定认证管理器
|
||||
.authenticationManager(authenticationManager)
|
||||
// 是否重复使用 refresh_token
|
||||
.reuseRefreshTokens(false)
|
||||
// 自定义异常处理
|
||||
.exceptionTranslator(new CustomWebResponseExceptionTranslator());
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置令牌端点(Token Endpoint)的安全约束
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
|
||||
{
|
||||
oauthServer.allowFormAuthenticationForClients().checkTokenAccess("permitAll()");
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明 ClientDetails实现
|
||||
*/
|
||||
public RedisClientDetailsService clientDetailsService()
|
||||
{
|
||||
RedisClientDetailsService clientDetailsService = new RedisClientDetailsService(dataSource);
|
||||
return clientDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置客户端详情
|
||||
*/
|
||||
@Override
|
||||
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
|
||||
{
|
||||
clients.withClientDetails(clientDetailsService());
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 Redis 实现,令牌保存到缓存
|
||||
*/
|
||||
@Bean
|
||||
public TokenStore tokenStore()
|
||||
{
|
||||
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
|
||||
tokenStore.setPrefix(CacheConstants.OAUTH_ACCESS);
|
||||
return tokenStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义生成令牌
|
||||
*/
|
||||
@Bean
|
||||
public TokenEnhancer tokenEnhancer()
|
||||
{
|
||||
return (accessToken, authentication) -> {
|
||||
if (authentication.getUserAuthentication() != null)
|
||||
{
|
||||
Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
|
||||
LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal();
|
||||
additionalInformation.put(SecurityConstants.DETAILS_USER_ID, user.getUserId());
|
||||
additionalInformation.put(SecurityConstants.DETAILS_USERNAME, user.getUsername());
|
||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
|
||||
}
|
||||
return accessToken;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package com.ruoyi.auth.config;
|
||||
|
||||
import com.ruoyi.common.security.service.UserDetailsServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
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;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* Security 安全认证相关配置
|
||||
* Oauth2依赖于Security 默认情况下WebSecurityConfig执行比ResourceServerConfig优先
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Order(99)
|
||||
@Configuration
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
|
||||
{
|
||||
// @Resource(name= "defaultUserDetailsService")
|
||||
// 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(getUserDetailsService()).passwordEncoder(passwordEncoder());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception
|
||||
{
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers(
|
||||
"/actuator/**",
|
||||
"/oauth/*",
|
||||
"/token/**",
|
||||
"/logout",
|
||||
"/login"
|
||||
).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and().csrf().disable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return new UserDetailsServiceImpl();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.ruoyi.auth.controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
|
@ -27,16 +29,16 @@ public class TokenController
|
|||
@Autowired
|
||||
private SysLoginService sysLoginService;
|
||||
|
||||
@PostMapping("login")
|
||||
public R<?> login(@RequestBody LoginBody form)
|
||||
{
|
||||
// 用户登录
|
||||
LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
|
||||
// 获取登录token
|
||||
return R.ok(tokenService.createToken(userInfo));
|
||||
}
|
||||
// @PostMapping("login")
|
||||
// public R<?> login(@RequestBody LoginBody form)
|
||||
// {
|
||||
// // 用户登录
|
||||
// UserInfo userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
|
||||
// // 获取登录token
|
||||
// return R.ok(tokenService.createToken(userInfo));
|
||||
// }
|
||||
|
||||
@DeleteMapping("logout")
|
||||
@DeleteMapping("token/logout")
|
||||
public R<?> logout(HttpServletRequest request)
|
||||
{
|
||||
LoginUser loginUser = tokenService.getLoginUser(request);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.ruoyi.auth.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* 身份信息获取
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/oauth")
|
||||
public class UserController
|
||||
{
|
||||
@RequestMapping("/user")
|
||||
public Principal user(Principal user)
|
||||
{
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.ruoyi.auth.exception;
|
||||
|
||||
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;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 自定义异常返回
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
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,39 @@
|
|||
package com.ruoyi.auth.handler;
|
||||
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.system.api.RemoteLogService;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 认证成功处理
|
||||
*
|
||||
* @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, "登录成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.ruoyi.auth.service;
|
||||
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
|
|
@ -7,7 +8,7 @@ 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.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.system.api.RemoteLogService;
|
||||
import com.ruoyi.system.api.RemoteUserService;
|
||||
|
|
@ -31,7 +32,7 @@ public class SysLoginService
|
|||
/**
|
||||
* 登录
|
||||
*/
|
||||
public LoginUser login(String username, String password)
|
||||
public UserInfo login(String username, String password)
|
||||
{
|
||||
// 用户名或密码为空 错误
|
||||
if (StringUtils.isAnyBlank(username, password))
|
||||
|
|
@ -54,7 +55,7 @@ public class SysLoginService
|
|||
throw new BaseException("用户名不在指定范围");
|
||||
}
|
||||
// 查询用户信息
|
||||
R<LoginUser> userResult = remoteUserService.getUserInfo(username);
|
||||
R<UserInfo> userResult = remoteUserService.getUserInfo(username);
|
||||
|
||||
if (R.FAIL == userResult.getCode())
|
||||
{
|
||||
|
|
@ -66,7 +67,7 @@ public class SysLoginService
|
|||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
|
||||
throw new BaseException("登录用户:" + username + " 不存在");
|
||||
}
|
||||
LoginUser userInfo = userResult.getData();
|
||||
UserInfo userInfo = userResult.getData();
|
||||
SysUser user = userResult.getData().getSysUser();
|
||||
if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,17 @@
|
|||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -36,4 +36,14 @@ public class CacheConstants
|
|||
* 授权信息字段
|
||||
*/
|
||||
public static final String AUTHORIZATION_HEADER = "authorization";
|
||||
|
||||
/**
|
||||
* oauth 缓存前缀
|
||||
*/
|
||||
public static final String OAUTH_ACCESS = "oauth:access:";
|
||||
|
||||
/**
|
||||
* oauth 客户端信息
|
||||
*/
|
||||
public static final String CLIENT_DETAILS_KEY = "oauth:client:details";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package com.ruoyi.common.core.constant;
|
||||
|
||||
/**
|
||||
* 权限相关通用常量
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class SecurityConstants
|
||||
{
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
public static final String BEARER_TOKEN_TYPE = "Bearer";
|
||||
|
||||
/**
|
||||
* 授权token url
|
||||
*/
|
||||
public static final String AUTH_TOKEN = "/oauth/token";
|
||||
|
||||
/**
|
||||
* 注销token url
|
||||
*/
|
||||
public static final String TOKEN_LOGOUT = "/token/logout";
|
||||
|
||||
/**
|
||||
* 用户ID字段
|
||||
*/
|
||||
public static final String DETAILS_USER_ID = "user_id";
|
||||
|
||||
/**
|
||||
* 用户名字段
|
||||
*/
|
||||
public static final String DETAILS_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* sys_oauth_client_details 表的字段,不包括client_id、client_secret
|
||||
*/
|
||||
public static final String CLIENT_FIELDS = "client_id, client_secret, resource_ids, scope, "
|
||||
+ "authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, "
|
||||
+ "refresh_token_validity, additional_information, autoapprove";
|
||||
|
||||
/**
|
||||
* JdbcClientDetailsService 查询语句
|
||||
*/
|
||||
public static final String BASE_FIND_STATEMENT = "select " + CLIENT_FIELDS + " from sys_oauth_client_details";
|
||||
|
||||
/**
|
||||
* 按条件client_id 查询
|
||||
*/
|
||||
public static final String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
|
||||
|
||||
/**
|
||||
* 默认的查询语句
|
||||
*/
|
||||
public static final String DEFAULT_FIND_STATEMENT = BASE_FIND_STATEMENT + " order by client_id";
|
||||
}
|
||||
|
|
@ -1,88 +1,91 @@
|
|||
package com.ruoyi.common.core.utils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
|
||||
/**
|
||||
* 权限获取工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class SecurityUtils
|
||||
{
|
||||
/**
|
||||
* 获取用户
|
||||
*/
|
||||
public static String getUsername()
|
||||
{
|
||||
String username = ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USERNAME);
|
||||
return ServletUtils.urlDecode(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户ID
|
||||
*/
|
||||
public static Long getUserId()
|
||||
{
|
||||
return Convert.toLong(ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USER_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
public static String getToken()
|
||||
{
|
||||
return getToken(ServletUtils.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据request获取请求token
|
||||
*/
|
||||
public static String getToken(HttpServletRequest request)
|
||||
{
|
||||
String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER);
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
{
|
||||
token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin(Long userId)
|
||||
{
|
||||
return userId != null && 1L == userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
}
|
||||
//package com.ruoyi.common.core.utils;
|
||||
//
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
//import com.ruoyi.common.core.constant.CacheConstants;
|
||||
//import com.ruoyi.common.core.text.Convert;
|
||||
//
|
||||
///**
|
||||
// * 权限获取工具类
|
||||
// *
|
||||
// * @author ruoyi
|
||||
// */
|
||||
//public class SecurityUtils
|
||||
//{
|
||||
// /**
|
||||
// * 获取用户
|
||||
// */
|
||||
// public static String getUsername()
|
||||
// {
|
||||
// String username = ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USERNAME);
|
||||
// return ServletUtils.urlDecode(username);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取用户ID
|
||||
// */
|
||||
// public static Long getUserId()
|
||||
// {
|
||||
// return Convert.toLong(ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USER_ID));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取请求token
|
||||
// */
|
||||
// public static String getToken()
|
||||
// {
|
||||
// return getToken(ServletUtils.getRequest());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 根据request获取请求token
|
||||
// */
|
||||
// public static String getToken(HttpServletRequest request)
|
||||
// {
|
||||
// String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER);
|
||||
// if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
// {
|
||||
// token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
// }
|
||||
// return token;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 是否为管理员
|
||||
// *
|
||||
// * @param userId 用户ID
|
||||
// * @return 结果
|
||||
// */
|
||||
// public static boolean isAdmin(Long userId)
|
||||
// {
|
||||
// return userId != null && 1L == userId;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 生成BCryptPasswordEncoder密码
|
||||
// *
|
||||
// * @param password 密码
|
||||
// * @return 加密字符串
|
||||
// */
|
||||
// public static String encryptPassword(String password)
|
||||
// {
|
||||
// BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
// return passwordEncoder.encode(password);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 判断密码是否相同
|
||||
// *
|
||||
// * @param rawPassword 真实密码
|
||||
// * @param encodedPassword 加密后字符
|
||||
// * @return 结果
|
||||
// */
|
||||
// public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
// {
|
||||
// BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
// return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
|
|
@ -20,7 +22,6 @@ import org.springframework.http.HttpMethod;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.ip.IpUtils;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,13 @@
|
|||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<!-- Spring Security Oauth2 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-oauth2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Api System -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import java.lang.annotation.Inherited;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.ruoyi.common.security.config.SecurityImportBeanDefinitionRegistrar;
|
||||
import com.ruoyi.common.security.feign.FeignConfig;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import com.ruoyi.common.security.config.ApplicationConfig;
|
||||
import com.ruoyi.common.security.feign.FeignAutoConfiguration;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
@ -24,8 +26,7 @@ import com.ruoyi.common.security.feign.FeignAutoConfiguration;
|
|||
// 开启线程异步执行
|
||||
@EnableAsync
|
||||
// 自动加载类
|
||||
@Import({ ApplicationConfig.class, FeignAutoConfiguration.class })
|
||||
public @interface EnableCustomConfig
|
||||
{
|
||||
@Import({ ApplicationConfig.class, FeignConfig.class , SecurityImportBeanDefinitionRegistrar.class})
|
||||
public @interface EnableCustomConfig {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Around;
|
|||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
|
@ -111,11 +112,11 @@ public class PreAuthorizeAspect
|
|||
public boolean hasPermi(String permission)
|
||||
{
|
||||
LoginUser userInfo = tokenService.getLoginUser();
|
||||
if (StringUtils.isEmpty(userInfo) || CollectionUtils.isEmpty(userInfo.getPermissions()))
|
||||
if (StringUtils.isEmpty(userInfo) || CollectionUtils.isEmpty(userInfo.getAuthorities()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return hasPermissions(userInfo.getPermissions(), permission);
|
||||
return hasPermissions(userInfo.getAuthorities(), permission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -142,7 +143,7 @@ public class PreAuthorizeAspect
|
|||
{
|
||||
return false;
|
||||
}
|
||||
Collection<String> authorities = userInfo.getPermissions();
|
||||
Collection<GrantedAuthority> authorities = userInfo.getAuthorities();
|
||||
for (String permission : permissions)
|
||||
{
|
||||
if (permission != null && hasPermissions(authorities, permission))
|
||||
|
|
@ -217,9 +218,8 @@ public class PreAuthorizeAspect
|
|||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
private boolean hasPermissions(Collection<String> authorities, String permission)
|
||||
private boolean hasPermissions(Collection<GrantedAuthority> authorities, String permission)
|
||||
{
|
||||
return authorities.stream().filter(StringUtils::hasText)
|
||||
.anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(permission, x));
|
||||
return authorities.stream().filter(grantedAuthority-> {return StringUtils.hasText(grantedAuthority.getAuthority());}).anyMatch(grantedAuthority -> ALL_PERMISSION.contains(grantedAuthority.getAuthority()) || PatternMatchUtils.simpleMatch(permission, grantedAuthority.getAuthority()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.ruoyi.common.security.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 忽略服务间的认证
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.ruoyi.common.security.config;
|
||||
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
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 java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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, 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");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
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 {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.ruoyi.common.security.config;
|
||||
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 导入 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,20 +1,20 @@
|
|||
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 FeignAutoConfiguration
|
||||
{
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor()
|
||||
{
|
||||
return new FeignRequestInterceptor();
|
||||
}
|
||||
}
|
||||
//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 FeignAutoConfiguration
|
||||
//{
|
||||
// @Bean
|
||||
// public RequestInterceptor requestInterceptor()
|
||||
// {
|
||||
// return new FeignRequestInterceptor();
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.ruoyi.common.security.feign;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Feign配置注册
|
||||
*
|
||||
* @author ruoyi
|
||||
**/
|
||||
@Configuration
|
||||
public class FeignConfig
|
||||
{
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor()
|
||||
{
|
||||
return new OAuth2FeignRequestInterceptor();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,45 @@
|
|||
package com.ruoyi.common.security.feign;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
|
||||
/**
|
||||
* feign 请求拦截器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class FeignRequestInterceptor implements RequestInterceptor
|
||||
{
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate)
|
||||
{
|
||||
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
|
||||
if (StringUtils.isNotNull(httpServletRequest))
|
||||
{
|
||||
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
|
||||
// 传递用户信息请求头,防止丢失
|
||||
String userId = headers.get(CacheConstants.DETAILS_USER_ID);
|
||||
if (StringUtils.isNotEmpty(userId))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId);
|
||||
}
|
||||
String userName = headers.get(CacheConstants.DETAILS_USERNAME);
|
||||
if (StringUtils.isNotEmpty(userName))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName);
|
||||
}
|
||||
String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.isNotEmpty(authentication))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.AUTHORIZATION_HEADER, authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//package com.ruoyi.common.security.feign;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import com.ruoyi.common.core.constant.CacheConstants;
|
||||
//import com.ruoyi.common.core.utils.ServletUtils;
|
||||
//import com.ruoyi.common.core.utils.StringUtils;
|
||||
//import feign.RequestInterceptor;
|
||||
//import feign.RequestTemplate;
|
||||
//
|
||||
///**
|
||||
// * feign 请求拦截器
|
||||
// *
|
||||
// * @author ruoyi
|
||||
// */
|
||||
//@Component
|
||||
//public class FeignRequestInterceptor implements RequestInterceptor
|
||||
//{
|
||||
// @Override
|
||||
// public void apply(RequestTemplate requestTemplate)
|
||||
// {
|
||||
// HttpServletRequest httpServletRequest = ServletUtils.getRequest();
|
||||
// if (StringUtils.isNotNull(httpServletRequest))
|
||||
// {
|
||||
// Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
|
||||
// // 传递用户信息请求头,防止丢失
|
||||
// String userId = headers.get(CacheConstants.DETAILS_USER_ID);
|
||||
// if (StringUtils.isNotEmpty(userId))
|
||||
// {
|
||||
// requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId);
|
||||
// }
|
||||
// String userName = headers.get(CacheConstants.DETAILS_USERNAME);
|
||||
// if (StringUtils.isNotEmpty(userName))
|
||||
// {
|
||||
// requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName);
|
||||
// }
|
||||
// String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER);
|
||||
// if (StringUtils.isNotEmpty(authentication))
|
||||
// {
|
||||
// requestTemplate.header(CacheConstants.AUTHORIZATION_HEADER, authentication);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.ruoyi.common.security.feign;
|
||||
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.ruoyi.common.security.handler;
|
||||
|
||||
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;
|
||||
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 javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 自定义访问无权限资源时的异常
|
||||
*
|
||||
* @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)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.ruoyi.common.security.handler;
|
||||
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.api.RemoteUserService;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author alikes
|
||||
*/
|
||||
@Component
|
||||
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||
if(authentication instanceof LoginUser){
|
||||
LoginUser loginUser = (LoginUser) authentication;
|
||||
R<UserInfo> res = remoteUserService.getUserInfo(loginUser.getSysUser().getUserName());
|
||||
loginUser.setRoles(res.getData().getRoles());
|
||||
loginUser.setPermissions(res.getData().getPermissions());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package com.ruoyi.common.security.service;
|
||||
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 自定义权限实现
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service("ss")
|
||||
public class PermissionService
|
||||
{
|
||||
/** 所有权限标识 */
|
||||
private static final String ALL_PERMISSION = "*:*:*";
|
||||
|
||||
/** 管理员角色权限标识 */
|
||||
private static final String SUPER_ADMIN = "admin";
|
||||
|
||||
private static final String ROLE_DELIMETER = ",";
|
||||
|
||||
private static final String PERMISSION_DELIMETER = ",";
|
||||
|
||||
/**
|
||||
* 验证用户是否具备某权限
|
||||
*
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public boolean hasPermi(String permission)
|
||||
{
|
||||
if (StringUtils.isEmpty(permission))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (StringUtils.isEmpty(loginUser) || CollectionUtils.isEmpty(loginUser.getAuthorities()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return hasPermissions(loginUser.getAuthorities(), permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否不具备某权限,与 hasPermi逻辑相反
|
||||
*
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否不具备某权限
|
||||
*/
|
||||
public boolean lacksPermi(String permission)
|
||||
{
|
||||
return hasPermi(permission) != true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否具有以下任意一个权限
|
||||
*
|
||||
* @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
|
||||
* @return 用户是否具有以下任意一个权限
|
||||
*/
|
||||
public boolean hasAnyPermi(String permissions)
|
||||
{
|
||||
if (StringUtils.isEmpty(permissions))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (StringUtils.isEmpty(loginUser) || CollectionUtils.isEmpty(loginUser.getAuthorities()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Collection<? extends GrantedAuthority> authorities = loginUser.getAuthorities();
|
||||
for (String permission : permissions.split(PERMISSION_DELIMETER))
|
||||
{
|
||||
if (permission != null && hasPermissions(authorities, permission))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否拥有某个角色
|
||||
*
|
||||
* @param role 角色字符串
|
||||
* @return 用户是否具备某角色
|
||||
*/
|
||||
public boolean hasRole(String role)
|
||||
{
|
||||
if (StringUtils.isEmpty(role))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (StringUtils.isEmpty(loginUser) || CollectionUtils.isEmpty(loginUser.getAuthorities()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (GrantedAuthority authorities : loginUser.getAuthorities())
|
||||
{
|
||||
String roleKey = authorities.getAuthority();
|
||||
if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(role))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否不具备某角色,与 isRole逻辑相反。
|
||||
*
|
||||
* @param role 角色名称
|
||||
* @return 用户是否不具备某角色
|
||||
*/
|
||||
public boolean lacksRole(String role)
|
||||
{
|
||||
return hasRole(role) != true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否具有以下任意一个角色
|
||||
*
|
||||
* @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
|
||||
* @return 用户是否具有以下任意一个角色
|
||||
*/
|
||||
public boolean hasAnyRoles(String roles)
|
||||
{
|
||||
if (StringUtils.isEmpty(roles))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (StringUtils.isEmpty(loginUser) || CollectionUtils.isEmpty(loginUser.getAuthorities()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (String role : roles.split(ROLE_DELIMETER))
|
||||
{
|
||||
if (hasRole(role))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含权限
|
||||
*
|
||||
* @param authorities 权限列表
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
private boolean hasPermissions(Collection<? extends GrantedAuthority> authorities, String permission)
|
||||
{
|
||||
return authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText)
|
||||
.anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(permission, x));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.ruoyi.common.security.service;
|
||||
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* 重写原生方法支持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);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,13 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
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.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.ip.IpUtils;
|
||||
|
|
@ -41,7 +42,7 @@ public class TokenService
|
|||
// 生成token
|
||||
String token = IdUtils.fastUUID();
|
||||
loginUser.setToken(token);
|
||||
loginUser.setUserid(loginUser.getSysUser().getUserId());
|
||||
loginUser.setUserId(loginUser.getSysUser().getUserId());
|
||||
loginUser.setUsername(loginUser.getSysUser().getUserName());
|
||||
loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
|
||||
refreshToken(loginUser);
|
||||
|
|
@ -71,15 +72,17 @@ public class TokenService
|
|||
*/
|
||||
public LoginUser getLoginUser(HttpServletRequest request)
|
||||
{
|
||||
// 获取请求携带的令牌
|
||||
String token = SecurityUtils.getToken(request);
|
||||
if (StringUtils.isNotEmpty(token))
|
||||
{
|
||||
String userKey = getTokenKey(token);
|
||||
LoginUser user = redisService.getCacheObject(userKey);
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
// // 获取请求携带的令牌
|
||||
// String token = SecurityUtils.getToken(request);
|
||||
// if (StringUtils.isNotEmpty(token))
|
||||
// {
|
||||
// String userKey = getTokenKey(token);
|
||||
// LoginUser user = redisService.getCacheObject(userKey);
|
||||
// LoginUser user = SecurityUtils.getLoginUser();
|
||||
//
|
||||
// }
|
||||
// return null;
|
||||
return SecurityUtils.getLoginUser();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
package com.ruoyi.common.security.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.system.api.RemoteUserService;
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
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 java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户信息处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service("defaultUserDetailsService")
|
||||
public class UserDetailsServiceImpl implements UserDetailsService
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
|
||||
@Override
|
||||
public LoginUser 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 LoginUser 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();
|
||||
LoginUser loginUser = new LoginUser(user.getUserId(), user.getUserName(), user.getPassword(), true, true, true, true, authorities);
|
||||
loginUser.setPermissions(info.getPermissions());
|
||||
loginUser.setRoles(info.getRoles());
|
||||
return loginUser;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package com.ruoyi.common.security.utils;
|
||||
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* 权限获取工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class SecurityUtils
|
||||
{
|
||||
/**
|
||||
* 获取Authentication
|
||||
*/
|
||||
public static Authentication getAuthentication()
|
||||
{
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
*/
|
||||
public static String getUsername()
|
||||
{
|
||||
return getLoginUser().getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
*/
|
||||
public static LoginUser getLoginUser(Authentication authentication)
|
||||
{
|
||||
Object principal = authentication.getPrincipal();
|
||||
if (principal instanceof LoginUser)
|
||||
{
|
||||
return (LoginUser) principal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户ID
|
||||
*/
|
||||
public static Long getUserId(){
|
||||
return Convert.toLong(getLoginUser().getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
*/
|
||||
public static LoginUser getLoginUser()
|
||||
{
|
||||
Authentication authentication = getAuthentication();
|
||||
if (authentication == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return getLoginUser(authentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin(Long userId)
|
||||
{
|
||||
return userId != null && 1L == userId;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,11 +13,7 @@ import com.google.common.base.Predicates;
|
|||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.ApiKey;
|
||||
import springfox.documentation.service.AuthorizationScope;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.service.SecurityReference;
|
||||
import springfox.documentation.service.*;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
|
@ -96,9 +92,20 @@ public class SwaggerAutoConfiguration
|
|||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.regex("^(?!auth).*$"))
|
||||
.build());
|
||||
securityContexts.add(SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
|
||||
.build());
|
||||
return securityContexts;
|
||||
}
|
||||
|
||||
// private SecurityContext securityContext(){
|
||||
// return SecurityContext.builder()
|
||||
// .securityReferences(defaultAuth())
|
||||
// .forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
|
||||
// .build();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 默认的全局鉴权策略
|
||||
*
|
||||
|
|
@ -114,6 +121,15 @@ public class SwaggerAutoConfiguration
|
|||
return securityReferences;
|
||||
}
|
||||
|
||||
private OAuth securitySchema()
|
||||
{
|
||||
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
|
||||
ArrayList<GrantType> grantTypes = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getTokenUrlList().forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
|
||||
return new OAuth(swaggerProperties().getAuthorization().getName(), authorizationScopeList, grantTypes);
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
|
||||
{
|
||||
return new ApiInfoBuilder()
|
||||
|
|
|
|||
|
|
@ -1,125 +1,125 @@
|
|||
package com.ruoyi.gateway.filter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 网关鉴权
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class AuthFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
|
||||
|
||||
private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
|
||||
|
||||
// 排除过滤的 uri 地址,nacos自行添加
|
||||
@Autowired
|
||||
private IgnoreWhiteProperties ignoreWhite;
|
||||
|
||||
@Resource(name = "stringRedisTemplate")
|
||||
private ValueOperations<String, String> sops;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
String url = exchange.getRequest().getURI().getPath();
|
||||
// 跳过不需要验证的路径
|
||||
if (StringUtils.matches(url, ignoreWhite.getWhites()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
String token = getToken(exchange.getRequest());
|
||||
if (StringUtils.isBlank(token))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "令牌不能为空");
|
||||
}
|
||||
String userStr = sops.get(getTokenKey(token));
|
||||
if (StringUtils.isNull(userStr))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "登录状态已过期");
|
||||
}
|
||||
JSONObject obj = JSONObject.parseObject(userStr);
|
||||
String userid = obj.getString("userid");
|
||||
String username = obj.getString("username");
|
||||
if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "令牌验证失败");
|
||||
}
|
||||
|
||||
// 设置过期时间
|
||||
redisService.expire(getTokenKey(token), EXPIRE_TIME);
|
||||
// 设置用户信息到请求
|
||||
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid)
|
||||
.header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
|
||||
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
|
||||
|
||||
return chain.filter(mutableExchange);
|
||||
}
|
||||
|
||||
private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
{
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
|
||||
return response.writeWith(Mono.fromSupplier(() -> {
|
||||
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||
return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
|
||||
}));
|
||||
}
|
||||
|
||||
private String getTokenKey(String token)
|
||||
{
|
||||
return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
private String getToken(ServerHttpRequest request)
|
||||
{
|
||||
String token = request.getHeaders().getFirst(CacheConstants.HEADER);
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
{
|
||||
token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -200;
|
||||
}
|
||||
}
|
||||
//package com.ruoyi.gateway.filter;
|
||||
//
|
||||
//import javax.annotation.Resource;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
//import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
//import org.springframework.core.Ordered;
|
||||
//import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
//import org.springframework.data.redis.core.ValueOperations;
|
||||
//import org.springframework.http.HttpStatus;
|
||||
//import org.springframework.http.MediaType;
|
||||
//import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
//import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.server.ServerWebExchange;
|
||||
//import com.alibaba.fastjson.JSON;
|
||||
//import com.alibaba.fastjson.JSONObject;
|
||||
//import com.ruoyi.common.core.constant.CacheConstants;
|
||||
//import com.ruoyi.common.core.constant.Constants;
|
||||
//import com.ruoyi.common.core.domain.R;
|
||||
//import com.ruoyi.common.core.utils.ServletUtils;
|
||||
//import com.ruoyi.common.core.utils.StringUtils;
|
||||
//import com.ruoyi.common.redis.service.RedisService;
|
||||
//import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
|
||||
//import reactor.core.publisher.Mono;
|
||||
//
|
||||
///**
|
||||
// * 网关鉴权
|
||||
// *
|
||||
// * @author ruoyi
|
||||
// */
|
||||
//@Component
|
||||
//public class AuthFilter implements GlobalFilter, Ordered
|
||||
//{
|
||||
// private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
|
||||
//
|
||||
// private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
|
||||
//
|
||||
// // 排除过滤的 uri 地址,nacos自行添加
|
||||
// @Autowired
|
||||
// private IgnoreWhiteProperties ignoreWhite;
|
||||
//
|
||||
// @Resource(name = "stringRedisTemplate")
|
||||
// private ValueOperations<String, String> sops;
|
||||
//
|
||||
// @Autowired
|
||||
// private RedisService redisService;
|
||||
//
|
||||
// @Override
|
||||
// public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
// {
|
||||
// String url = exchange.getRequest().getURI().getPath();
|
||||
// // 跳过不需要验证的路径
|
||||
// if (StringUtils.matches(url, ignoreWhite.getWhites()))
|
||||
// {
|
||||
// return chain.filter(exchange);
|
||||
// }
|
||||
// String token = getToken(exchange.getRequest());
|
||||
// if (StringUtils.isBlank(token))
|
||||
// {
|
||||
// return setUnauthorizedResponse(exchange, "令牌不能为空");
|
||||
// }
|
||||
// String userStr = sops.get(getTokenKey(token));
|
||||
// if (StringUtils.isNull(userStr))
|
||||
// {
|
||||
// return setUnauthorizedResponse(exchange, "登录状态已过期");
|
||||
// }
|
||||
// JSONObject obj = JSONObject.parseObject(userStr);
|
||||
// String userid = obj.getString("userid");
|
||||
// String username = obj.getString("username");
|
||||
// if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
|
||||
// {
|
||||
// return setUnauthorizedResponse(exchange, "令牌验证失败");
|
||||
// }
|
||||
//
|
||||
// // 设置过期时间
|
||||
// redisService.expire(getTokenKey(token), EXPIRE_TIME);
|
||||
// // 设置用户信息到请求
|
||||
// ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid)
|
||||
// .header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
|
||||
// ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
|
||||
//
|
||||
// return chain.filter(mutableExchange);
|
||||
// }
|
||||
//
|
||||
// private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
// {
|
||||
// ServerHttpResponse response = exchange.getResponse();
|
||||
// response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
// response.setStatusCode(HttpStatus.OK);
|
||||
//
|
||||
// log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
//
|
||||
// return response.writeWith(Mono.fromSupplier(() -> {
|
||||
// DataBufferFactory bufferFactory = response.bufferFactory();
|
||||
// return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
|
||||
// }));
|
||||
// }
|
||||
//
|
||||
// private String getTokenKey(String token)
|
||||
// {
|
||||
// return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取请求token
|
||||
// */
|
||||
// private String getToken(ServerHttpRequest request)
|
||||
// {
|
||||
// String token = request.getHeaders().getFirst(CacheConstants.HEADER);
|
||||
// if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
// {
|
||||
// token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
// }
|
||||
// return token;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getOrder()
|
||||
// {
|
||||
// return -200;
|
||||
// }
|
||||
//}
|
||||
|
|
@ -16,14 +16,15 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
sentinel:
|
||||
# 取消控制台懒加载
|
||||
eager: true
|
||||
|
|
@ -34,7 +35,7 @@ spring:
|
|||
datasource:
|
||||
ds1:
|
||||
nacos:
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
dataId: sentinel-ruoyi-gateway
|
||||
groupId: DEFAULT_GROUP
|
||||
data-type: json
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -25,7 +25,7 @@ import com.ruoyi.common.core.constant.Constants;
|
|||
import com.ruoyi.common.core.constant.GenConstants;
|
||||
import com.ruoyi.common.core.exception.CustomException;
|
||||
import com.ruoyi.common.core.text.CharsetKit;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.file.FileUtils;
|
||||
import com.ruoyi.gen.domain.GenTable;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ 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.exception.job.TaskException;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,33 @@
|
|||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Api System -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-api-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
|
|
@ -145,6 +172,10 @@
|
|||
<version>1.16.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.ruoyi</groupId>-->
|
||||
<!-- <artifactId>ruoyi-common-security</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -17,15 +17,20 @@ package com.alibaba.csp.sentinel.dashboard;
|
|||
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
|
||||
//import com.ruoyi.common.security.annotation.EnableCustomConfig;
|
||||
//import com.ruoyi.common.security.annotation.EnableRyFeignClients;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* Sentinel dashboard application.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
*/
|
||||
@SpringBootApplication
|
||||
//@EnableCustomConfig
|
||||
//@EnableRyFeignClients
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
public class RuoYiSentinelDashboardApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ public class WebConfig implements WebMvcConfigurer {
|
|||
|
||||
private final Logger logger = LoggerFactory.getLogger(WebConfig.class);
|
||||
|
||||
@Autowired
|
||||
private LoginAuthenticationFilter loginAuthenticationFilter;
|
||||
// @Autowired
|
||||
// private LoginAuthenticationFilter loginAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private AuthorizationInterceptor authorizationInterceptor;
|
||||
|
|
@ -104,13 +104,13 @@ public class WebConfig implements WebMvcConfigurer {
|
|||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean authenticationFilterRegistration() {
|
||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(loginAuthenticationFilter);
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("authenticationFilter");
|
||||
registration.setOrder(0);
|
||||
return registration;
|
||||
}
|
||||
// @Bean
|
||||
// public FilterRegistrationBean authenticationFilterRegistration() {
|
||||
// FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
// registration.setFilter(loginAuthenticationFilter);
|
||||
// registration.addUrlPatterns("/*");
|
||||
// registration.setName("authenticationFilter");
|
||||
// registration.setOrder(0);
|
||||
// return registration;
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.alibaba.csp.sentinel.dashboard.controller.v2;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制器基类
|
||||
* @author alikes
|
||||
*/
|
||||
public class BaseController {
|
||||
|
||||
}
|
||||
|
|
@ -19,14 +19,13 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -51,7 +50,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/v2/flow")
|
||||
public class FlowControllerV2 {
|
||||
public class FlowControllerV2 extends BaseController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 降级规则
|
||||
* @author alikes
|
||||
*/
|
||||
@Component("degradeRuleNacosProvider")
|
||||
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private Converter<String, List<DegradeRuleEntity>> converter;
|
||||
|
||||
@Override
|
||||
public List<DegradeRuleEntity> getRules(String appName) throws Exception {
|
||||
String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
|
||||
NacosConfigUtil.GROUP_ID, 3000);
|
||||
if (StringUtil.isEmpty(rules)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return converter.convert(rules);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@Component("degradeRuleNacosPublisher")
|
||||
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
@Autowired
|
||||
private Converter<List<DegradeRuleEntity>, String> converter;
|
||||
|
||||
@Override
|
||||
public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
|
||||
AssertUtil.notEmpty(app, "app name cannot be empty");
|
||||
if (rules == null) {
|
||||
return;
|
||||
}
|
||||
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
|
||||
NacosConfigUtil.GROUP_ID, converter.convert(rules));
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
|
@ -36,7 +37,7 @@ import java.util.Properties;
|
|||
@Configuration
|
||||
public class NacosConfig {
|
||||
|
||||
@Value("${spring.nacos.server-addr}")
|
||||
@Value("${spring.cloud.nacos.config.server-addr}")
|
||||
private String serverAddr;
|
||||
|
||||
@Bean
|
||||
|
|
@ -49,6 +50,16 @@ public class NacosConfig {
|
|||
return s -> JSON.parseArray(s, FlowRuleEntity.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
|
||||
return JSON::toJSONString;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
|
||||
return s -> JSON.parseArray(s, DegradeRuleEntity.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigService nacosConfigService() throws Exception {
|
||||
if(StringUtils.isEmpty(serverAddr)){//不配置时,使用默认配置
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
#spring settings
|
||||
spring.http.encoding.force=true
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
|
||||
#cookie name setting
|
||||
server.servlet.session.cookie.name=sentinel_dashboard_cookie
|
||||
|
||||
#logging settings
|
||||
logging.level.org.springframework.web=INFO
|
||||
logging.file=${user.home}/logs/csp/sentinel-dashboard.log
|
||||
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
|
||||
#auth settings
|
||||
auth.filter.exclude-urls=/,/auth/login,/auth/logout,/registry/machine,/version
|
||||
auth.filter.exclude-url-suffixes=htm,html,js,css,map,ico,ttf,woff,png
|
||||
# If auth.enabled=false, Sentinel console disable login
|
||||
auth.username=sentinel
|
||||
auth.password=sentinel
|
||||
|
||||
# Inject the dashboard version. It's required to enable
|
||||
# filtering in pom.xml for this resource file.
|
||||
sentinel.dashboard.version=${project.version}
|
||||
spring.nacos.server-addr=127.0.0.1:8848
|
||||
server.port=8718
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
## Tomcat
|
||||
#server:
|
||||
# port: 8718
|
||||
# servlet:
|
||||
# encoding:
|
||||
# enabled: true
|
||||
# force: true
|
||||
# charset: UTF-8
|
||||
# session:
|
||||
# cookie:
|
||||
# name: sentinel_dashboard_cookie
|
||||
#logging:
|
||||
# level:
|
||||
# org:
|
||||
# springframework:
|
||||
# web: INFO
|
||||
# file:
|
||||
# name: ${user.home}/logs/csp/sentinel-dashboard.log
|
||||
# pattern:
|
||||
# file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
||||
#auth:
|
||||
# filter:
|
||||
# exclude-urls: "/,/auth/login,/auth/logout,/registry/machine,/version"
|
||||
# exclude-url-suffixes: "htm,html,js,css,map,ico,ttf,woff,png"
|
||||
# username: sentinel
|
||||
# password: sentinel
|
||||
#sentinel:
|
||||
# dashboard:
|
||||
# version: ${project.version}
|
||||
## Spring
|
||||
#spring:
|
||||
# application:
|
||||
# # 应用名称
|
||||
# name: ruoyi-sentinel
|
||||
# profiles:
|
||||
# # 环境配置
|
||||
# active: dev
|
||||
# cloud:
|
||||
# nacos:
|
||||
# discovery:
|
||||
# # 服务注册地址
|
||||
# server-addr: 175.25.50.135:8848
|
||||
# config:
|
||||
# # 配置中心地址
|
||||
# server-addr: 175.25.50.135:8848
|
||||
# # 配置文件格式
|
||||
# file-extension: yml
|
||||
# # 共享配置
|
||||
# shared-configs:
|
||||
# - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
sentinel:
|
||||
dashboard:
|
||||
version: ${project.version}
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: ruoyi-sentinel
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
var app = angular.module('sentinelDashboardApp');
|
||||
|
||||
app.controller('DegradeCtl', ['$scope', '$stateParams', 'DegradeService', 'ngDialog', 'MachineService',
|
||||
function ($scope, $stateParams, DegradeService, ngDialog, MachineService) {
|
||||
//初始化
|
||||
$scope.app = $stateParams.app;
|
||||
$scope.rulesPageConfig = {
|
||||
pageSize: 10,
|
||||
currentPageIndex: 1,
|
||||
totalPage: 1,
|
||||
totalCount: 0,
|
||||
};
|
||||
$scope.macsInputConfig = {
|
||||
searchField: ['text', 'value'],
|
||||
persist: true,
|
||||
create: false,
|
||||
maxItems: 1,
|
||||
render: {
|
||||
item: function (data, escape) {
|
||||
return '<div>' + escape(data.text) + '</div>';
|
||||
}
|
||||
},
|
||||
onChange: function (value, oldValue) {
|
||||
$scope.macInputModel = value;
|
||||
}
|
||||
};
|
||||
getMachineRules();
|
||||
function getMachineRules() {
|
||||
if (!$scope.macInputModel) {
|
||||
return;
|
||||
}
|
||||
var mac = $scope.macInputModel.split(':');
|
||||
DegradeService.queryMachineRules($scope.app, mac[0], mac[1]).success(
|
||||
function (data) {
|
||||
if (data.code == 0 && data.data) {
|
||||
$scope.rules = data.data;
|
||||
$scope.rulesPageConfig.totalCount = $scope.rules.length;
|
||||
} else {
|
||||
$scope.rules = [];
|
||||
$scope.rulesPageConfig.totalCount = 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.getMachineRules = getMachineRules;
|
||||
|
||||
var degradeRuleDialog;
|
||||
$scope.editRule = function (rule) {
|
||||
$scope.currentRule = angular.copy(rule);
|
||||
$scope.degradeRuleDialog = {
|
||||
title: '编辑降级规则',
|
||||
type: 'edit',
|
||||
confirmBtnText: '保存'
|
||||
};
|
||||
degradeRuleDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/degrade-rule-dialog.html',
|
||||
width: 680,
|
||||
overlay: true,
|
||||
scope: $scope
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addNewRule = function () {
|
||||
var mac = $scope.macInputModel.split(':');
|
||||
$scope.currentRule = {
|
||||
grade: 0,
|
||||
app: $scope.app,
|
||||
ip: mac[0],
|
||||
port: mac[1],
|
||||
limitApp: 'default',
|
||||
minRequestAmount: 5,
|
||||
statIntervalMs: 1000,
|
||||
};
|
||||
$scope.degradeRuleDialog = {
|
||||
title: '新增降级规则',
|
||||
type: 'add',
|
||||
confirmBtnText: '新增'
|
||||
};
|
||||
degradeRuleDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/degrade-rule-dialog.html',
|
||||
width: 680,
|
||||
overlay: true,
|
||||
scope: $scope
|
||||
});
|
||||
};
|
||||
|
||||
$scope.saveRule = function () {
|
||||
if (!DegradeService.checkRuleValid($scope.currentRule)) {
|
||||
return;
|
||||
}
|
||||
if ($scope.degradeRuleDialog.type === 'add') {
|
||||
addNewRule($scope.currentRule);
|
||||
} else if ($scope.degradeRuleDialog.type === 'edit') {
|
||||
saveRule($scope.currentRule, true);
|
||||
}
|
||||
};
|
||||
|
||||
function parseDegradeMode(grade) {
|
||||
switch (grade) {
|
||||
case 0:
|
||||
return '慢调用比例';
|
||||
case 1:
|
||||
return '异常比例';
|
||||
case 2:
|
||||
return '异常数';
|
||||
default:
|
||||
return '未知';
|
||||
}
|
||||
}
|
||||
|
||||
var confirmDialog;
|
||||
$scope.deleteRule = function (rule) {
|
||||
$scope.currentRule = rule;
|
||||
$scope.confirmDialog = {
|
||||
title: '删除降级规则',
|
||||
type: 'delete_rule',
|
||||
attentionTitle: '请确认是否删除如下降级规则',
|
||||
attention: '资源名: ' + rule.resource +
|
||||
', 降级模式: ' + parseDegradeMode(rule.grade) + ', 阈值: ' + rule.count,
|
||||
confirmBtnText: '删除',
|
||||
};
|
||||
confirmDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/confirm-dialog.html',
|
||||
scope: $scope,
|
||||
overlay: true
|
||||
});
|
||||
};
|
||||
|
||||
$scope.confirm = function () {
|
||||
if ($scope.confirmDialog.type == 'delete_rule') {
|
||||
deleteRule($scope.currentRule);
|
||||
} else {
|
||||
console.error('error');
|
||||
}
|
||||
};
|
||||
|
||||
function deleteRule(rule) {
|
||||
DegradeService.deleteRule(rule).success(function (data) {
|
||||
if (data.code == 0) {
|
||||
getMachineRules();
|
||||
confirmDialog.close();
|
||||
} else {
|
||||
alert('失败:' + data.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function addNewRule(rule) {
|
||||
DegradeService.newRule(rule).success(function (data) {
|
||||
if (data.code == 0) {
|
||||
getMachineRules();
|
||||
degradeRuleDialog.close();
|
||||
} else {
|
||||
alert('失败:' + data.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function saveRule(rule, edit) {
|
||||
DegradeService.saveRule(rule).success(function (data) {
|
||||
if (data.code == 0) {
|
||||
getMachineRules();
|
||||
if (edit) {
|
||||
degradeRuleDialog.close();
|
||||
} else {
|
||||
confirmDialog.close();
|
||||
}
|
||||
} else {
|
||||
alert('失败:' + data.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
queryAppMachines();
|
||||
function queryAppMachines() {
|
||||
MachineService.getAppMachines($scope.app).success(
|
||||
function (data) {
|
||||
if (data.code == 0) {
|
||||
// $scope.machines = data.data;
|
||||
if (data.data) {
|
||||
$scope.machines = [];
|
||||
$scope.macsInputOptions = [];
|
||||
data.data.forEach(function (item) {
|
||||
if (item.healthy) {
|
||||
$scope.macsInputOptions.push({
|
||||
text: item.ip + ':' + item.port,
|
||||
value: item.ip + ':' + item.port
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if ($scope.macsInputOptions.length > 0) {
|
||||
$scope.macInputModel = $scope.macsInputOptions[0].value;
|
||||
}
|
||||
} else {
|
||||
$scope.macsInputOptions = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
$scope.$watch('macInputModel', function () {
|
||||
if ($scope.macInputModel) {
|
||||
getMachineRules();
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
var app = angular.module('sentinelDashboardApp');
|
||||
|
||||
app.service('DegradeService', ['$http', function ($http) {
|
||||
this.queryMachineRules = function (app, ip, port) {
|
||||
var param = {
|
||||
app: app,
|
||||
ip: ip,
|
||||
port: port
|
||||
};
|
||||
return $http({
|
||||
url: '/V2/degrade/rules',
|
||||
params: param,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
this.newRule = function (rule) {
|
||||
return $http({
|
||||
url: '/degrade/rule',
|
||||
data: rule,
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
this.saveRule = function (rule) {
|
||||
var param = {
|
||||
id: rule.id,
|
||||
resource: rule.resource,
|
||||
limitApp: rule.limitApp,
|
||||
grade: rule.grade,
|
||||
count: rule.count,
|
||||
timeWindow: rule.timeWindow,
|
||||
statIntervalMs: rule.statIntervalMs,
|
||||
minRequestAmount: rule.minRequestAmount,
|
||||
slowRatioThreshold: rule.slowRatioThreshold,
|
||||
};
|
||||
return $http({
|
||||
url: '/degrade/rule/' + rule.id,
|
||||
data: param,
|
||||
method: 'PUT'
|
||||
});
|
||||
};
|
||||
|
||||
this.deleteRule = function (rule) {
|
||||
return $http({
|
||||
url: '/degrade/rule/' + rule.id,
|
||||
method: 'DELETE'
|
||||
});
|
||||
};
|
||||
|
||||
this.checkRuleValid = function (rule) {
|
||||
if (rule.resource === undefined || rule.resource === '') {
|
||||
alert('资源名称不能为空');
|
||||
return false;
|
||||
}
|
||||
if (rule.grade === undefined || rule.grade < 0) {
|
||||
alert('未知的降级策略');
|
||||
return false;
|
||||
}
|
||||
if (rule.count === undefined || rule.count === '' || rule.count < 0) {
|
||||
alert('降级阈值不能为空或小于 0');
|
||||
return false;
|
||||
}
|
||||
if (rule.timeWindow == undefined || rule.timeWindow === '' || rule.timeWindow <= 0) {
|
||||
alert('熔断时长必须大于 0s');
|
||||
return false;
|
||||
}
|
||||
if (rule.minRequestAmount == undefined || rule.minRequestAmount <= 0) {
|
||||
alert('最小请求数目需大于 0');
|
||||
return false;
|
||||
}
|
||||
if (rule.statIntervalMs == undefined || rule.statIntervalMs <= 0) {
|
||||
alert('统计窗口时长需大于 0s');
|
||||
return false;
|
||||
}
|
||||
if (rule.statIntervalMs !== undefined && rule.statIntervalMs > 60 * 1000 * 2) {
|
||||
alert('统计窗口时长不能超过 120 分钟');
|
||||
return false;
|
||||
}
|
||||
// 异常比率类型.
|
||||
if (rule.grade == 1 && rule.count > 1) {
|
||||
alert('异常比率超出范围:[0.0 - 1.0]');
|
||||
return false;
|
||||
}
|
||||
if (rule.grade == 0) {
|
||||
if (rule.slowRatioThreshold == undefined) {
|
||||
alert('慢调用比率不能为空');
|
||||
return false;
|
||||
}
|
||||
if (rule.slowRatioThreshold < 0 || rule.slowRatioThreshold > 1) {
|
||||
alert('慢调用比率超出范围:[0.0 - 1.0]');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}]);
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;">
|
||||
<div class="col-md-6" style="margin-bottom: 10px;">
|
||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()">
|
||||
<i class="fa fa-plus"></i> 新增降级规则</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="inputs-header">
|
||||
<span class="brand" style="font-size: 13px;">降级规则</span>
|
||||
<!--<button class="btn btn-danger" style="float: right;margin-right: 10px;height: 30px;font-size: 12px;" ng-click="disableAll()">全部禁用</button>-->
|
||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button>
|
||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey">
|
||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;">
|
||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel"
|
||||
placeholder="机器"></selectize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--.tools-header -->
|
||||
<div class="card-body" style="padding: 0px 0px;">
|
||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;">
|
||||
<thead>
|
||||
<tr style="background: #F3F5F7;">
|
||||
<td style="width: 40%">
|
||||
资源名
|
||||
</td>
|
||||
<td style="width: 10%;">
|
||||
降级策略
|
||||
</td>
|
||||
<td style="width: 10%;">
|
||||
阈值
|
||||
</td>
|
||||
<td style="width: 10%;">
|
||||
熔断时长(s)
|
||||
</td>
|
||||
<td style="width: 12%;">
|
||||
操作
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="rule in rules | filter : searchKey | itemsPerPage: rulesPageConfig.pageSize " current-page="rulesPageConfig.currentPageIndex"
|
||||
pagination-id="entriesPagination">
|
||||
<td style="word-wrap:break-word;word-break:break-all;">{{rule.resource}}</td>
|
||||
<!--<td style="word-wrap:break-word;word-break:break-all;">{{rule.limitApp }}</td>-->
|
||||
<td>
|
||||
<span ng-if="rule.grade == 0">慢调用比例</span>
|
||||
<span ng-if="rule.grade == 1" title="异常比例">异常比例</span>
|
||||
<span ng-if="rule.grade == 2" title="异常数">异常数</span>
|
||||
</td>
|
||||
<td style="word-wrap:break-word;word-break:break-all;">
|
||||
{{rule.count}}
|
||||
</td>
|
||||
<td style="word-wrap:break-word;word-break:break-all;">
|
||||
{{rule.timeWindow}}s
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button>
|
||||
<button class="btn btn-xs btn-default" type="button" ng-click="deleteRule(rule)" style="font-size: 12px; height:25px;">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- .card-body -->
|
||||
<div class="pagination-footer">
|
||||
<dir-pagination-controls boundary-links="true" template-url="app/views/pagination.tpl.html" pagination-id="entriesPagination"
|
||||
on-page-change="">
|
||||
</dir-pagination-controls>
|
||||
<div class="tools" style="">
|
||||
<span>共 {{rulesPageConfig.totalCount}} 条记录, </span>
|
||||
<span>
|
||||
每页
|
||||
<input class="form-control" ng-model="rulesPageConfig.pageSize"> 条记录,
|
||||
</span>
|
||||
<span>第 {{rulesPageConfig.currentPageIndex}} / {{rulesPageConfig.totalPage}} 页</span>
|
||||
</div>
|
||||
<!-- .tools -->
|
||||
</div>
|
||||
<!-- pagination-footer -->
|
||||
</div>
|
||||
<!-- .card -->
|
||||
</div>
|
||||
<!-- .col-md-12 -->
|
||||
</div>
|
||||
<!-- -->
|
||||
</div>
|
||||
<!-- .container-fluid -->
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,7 +14,7 @@ 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.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ 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.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
|
|
@ -14,7 +16,6 @@ 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.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ 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.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ 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.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.web.page.TableDataInfo;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ 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.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ 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.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.system.api.model.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
|
@ -18,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.core.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
|
|
@ -101,7 +104,7 @@ public class SysUserController extends BaseController
|
|||
* 获取当前用户信息
|
||||
*/
|
||||
@GetMapping("/info/{username}")
|
||||
public R<LoginUser> info(@PathVariable("username") String username)
|
||||
public R<UserInfo> info(@PathVariable("username") String username)
|
||||
{
|
||||
SysUser sysUser = userService.selectUserByUserName(username);
|
||||
if (StringUtils.isNull(sysUser))
|
||||
|
|
@ -112,7 +115,7 @@ public class SysUserController extends BaseController
|
|||
Set<String> roles = permissionService.getRolePermission(sysUser.getUserId());
|
||||
// 权限集合
|
||||
Set<String> permissions = permissionService.getMenuPermission(sysUser.getUserId());
|
||||
LoginUser sysUserVo = new LoginUser();
|
||||
UserInfo sysUserVo = new UserInfo();
|
||||
sysUserVo.setSysUser(sysUser);
|
||||
sysUserVo.setRoles(roles);
|
||||
sysUserVo.setPermissions(permissions);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import java.util.stream.Collectors;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.core.constant.UserConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.system.api.domain.SysRole;
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.common.core.constant.UserConstants;
|
||||
import com.ruoyi.common.core.exception.CustomException;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.security.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.datascope.annotation.DataScope;
|
||||
import com.ruoyi.system.api.domain.SysRole;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
|
|||
|
|
@ -1,46 +1,90 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
const client_id = 'web'
|
||||
const client_secret = '123456'
|
||||
const scope = 'server'
|
||||
|
||||
// 登录方法
|
||||
export function login(username, password, code, uuid) {
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
method: 'post',
|
||||
data: { username, password, code, uuid }
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新方法
|
||||
export function refreshToken() {
|
||||
return request({
|
||||
url: '/auth/refresh',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return request({
|
||||
url: '/system/user/getInfo',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 退出方法
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/auth/logout',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function getCodeImg() {
|
||||
return request({
|
||||
url: '/code',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
import request from '@/utils/request'
|
||||
|
||||
const client_id = 'web'
|
||||
const client_secret = '123456'
|
||||
const scope = 'server'
|
||||
|
||||
// // 登录方法
|
||||
// export function login(username, password, code, uuid) {
|
||||
// return request({
|
||||
// url: '/auth/login',
|
||||
// method: 'post',
|
||||
// data: { username, password, code, uuid }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// // 刷新方法
|
||||
// export function refreshToken() {
|
||||
// return request({
|
||||
// url: '/auth/refresh',
|
||||
// method: 'post'
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// // 获取用户详细信息
|
||||
// export function getInfo() {
|
||||
// return request({
|
||||
// url: '/system/user/getInfo',
|
||||
// method: 'get'
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// // 退出方法
|
||||
// export function logout() {
|
||||
// return request({
|
||||
// url: '/auth/logout',
|
||||
// method: 'delete'
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// // 获取验证码
|
||||
// export function getCodeImg() {
|
||||
// return request({
|
||||
// url: '/code',
|
||||
// method: 'get'
|
||||
// })
|
||||
// }
|
||||
|
||||
// 登录方法
|
||||
export function login(username, password, code, uuid) {
|
||||
const grant_type = 'password'
|
||||
return request({
|
||||
url: '/auth/oauth/token',
|
||||
method: 'post',
|
||||
params: { username, password, code, uuid, client_id, client_secret, grant_type, scope }
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新方法
|
||||
export function refreshToken(refresh_token) {
|
||||
const grant_type = 'refresh_token'
|
||||
return request({
|
||||
url: '/auth/oauth/token',
|
||||
method: 'post',
|
||||
params: { client_id, client_secret, grant_type, scope, refresh_token }
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return request({
|
||||
url: '/system/user/getInfo',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 退出方法
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/auth/token/logout',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function getCodeImg() {
|
||||
return request({
|
||||
url: '/code',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,115 +1,156 @@
|
|||
import { login, logout, getInfo, refreshToken } from '@/api/login'
|
||||
import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
permissions: []
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_EXPIRES_IN: (state, time) => {
|
||||
state.expires_in = time
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 登录
|
||||
Login({ commit }, userInfo) {
|
||||
const username = userInfo.username.trim()
|
||||
const password = userInfo.password
|
||||
const code = userInfo.code
|
||||
const uuid = userInfo.uuid
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, uuid).then(res => {
|
||||
let data = res.data
|
||||
setToken(data.access_token)
|
||||
commit('SET_TOKEN', data.access_token)
|
||||
setExpiresIn(data.expires_in)
|
||||
commit('SET_EXPIRES_IN', data.expires_in)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo(state.token).then(res => {
|
||||
const user = res.user
|
||||
const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : user.avatar;
|
||||
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
commit('SET_ROLES', res.roles)
|
||||
commit('SET_PERMISSIONS', res.permissions)
|
||||
} else {
|
||||
commit('SET_ROLES', ['ROLE_DEFAULT'])
|
||||
}
|
||||
commit('SET_NAME', user.userName)
|
||||
commit('SET_AVATAR', avatar)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新token
|
||||
RefreshToken({commit, state}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
refreshToken(state.token).then(res => {
|
||||
setExpiresIn(res.data)
|
||||
commit('SET_EXPIRES_IN', res.data)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(state.token).then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
removeToken()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 前端 登出
|
||||
FedLogOut({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default user
|
||||
import { login, logout, getInfo, refreshToken } from '@/api/login'
|
||||
import { getToken, setToken,getRefreshToken, setRefreshToken, setExpiresIn, removeToken } from '@/utils/auth'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
refresh_token: getRefreshToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
permissions: []
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_EXPIRES_IN: (state, time) => {
|
||||
state.expires_in = time
|
||||
},
|
||||
SET_REFRESH_TOKEN: (state, token) => {
|
||||
state.refresh_token = token
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// // 登录
|
||||
// Login({ commit }, userInfo) {
|
||||
// const username = userInfo.username.trim()
|
||||
// const password = userInfo.password
|
||||
// const code = userInfo.code
|
||||
// const uuid = userInfo.uuid
|
||||
// return new Promise((resolve, reject) => {
|
||||
// login(username, password, code, uuid).then(res => {
|
||||
// let data = res.data
|
||||
// setToken(data.access_token)
|
||||
// commit('SET_TOKEN', data.access_token)
|
||||
// setExpiresIn(data.expires_in)
|
||||
// commit('SET_EXPIRES_IN', data.expires_in)
|
||||
// resolve()
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
// 登录
|
||||
Login({ commit }, userInfo) {
|
||||
const username = userInfo.username.trim()
|
||||
const password = userInfo.password
|
||||
const code = userInfo.code
|
||||
const uuid = userInfo.uuid
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, uuid).then(res => {
|
||||
setToken(res.access_token)
|
||||
commit('SET_TOKEN', res.access_token)
|
||||
setRefreshToken(res.refresh_token)
|
||||
commit('SET_REFRESH_TOKEN', res.refresh_token)
|
||||
setExpiresIn(res.expires_in)
|
||||
commit('SET_EXPIRES_IN', res.expires_in)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo(state.token).then(res => {
|
||||
const user = res.user
|
||||
const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : user.avatar;
|
||||
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
commit('SET_ROLES', res.roles)
|
||||
commit('SET_PERMISSIONS', res.permissions)
|
||||
} else {
|
||||
commit('SET_ROLES', ['ROLE_DEFAULT'])
|
||||
}
|
||||
commit('SET_NAME', user.userName)
|
||||
commit('SET_AVATAR', avatar)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// // 刷新token
|
||||
// RefreshToken({commit, state}) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// refreshToken(state.token).then(res => {
|
||||
// setExpiresIn(res.data)
|
||||
// commit('SET_EXPIRES_IN', res.data)
|
||||
// resolve()
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
// 刷新token
|
||||
RefreshToken({commit, state}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
refreshToken(state.refresh_token).then(res => {
|
||||
setToken(res.access_token)
|
||||
commit('SET_TOKEN', res.access_token)
|
||||
setRefreshToken(res.refresh_token)
|
||||
commit('SET_REFRESH_TOKEN', res.refresh_token)
|
||||
setExpiresIn(res.expires_in)
|
||||
commit('SET_EXPIRES_IN', res.expires_in)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(state.token).then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
removeToken()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 前端 登出
|
||||
FedLogOut({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default user
|
||||
|
|
|
|||
|
|
@ -1,29 +1,41 @@
|
|||
import Cookies from 'js-cookie'
|
||||
|
||||
const TokenKey = 'Admin-Token'
|
||||
|
||||
const ExpiresInKey = 'Admin-Expires-In'
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token)
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
|
||||
export function getExpiresIn() {
|
||||
return Cookies.get(ExpiresInKey) || -1
|
||||
}
|
||||
|
||||
export function setExpiresIn(time) {
|
||||
return Cookies.set(ExpiresInKey, time)
|
||||
}
|
||||
|
||||
export function removeExpiresIn() {
|
||||
return Cookies.remove(ExpiresInKey)
|
||||
}
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const TokenKey = 'Admin-Token'
|
||||
const RefreshTokenKey = 'Admin-Refresh-Token'
|
||||
const ExpiresInKey = 'Admin-Expires-In'
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token)
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
|
||||
export function getRefreshToken() {
|
||||
return Cookies.get(RefreshTokenKey) || ``
|
||||
}
|
||||
|
||||
export function setRefreshToken(token) {
|
||||
return Cookies.set(RefreshTokenKey, token)
|
||||
}
|
||||
|
||||
export function removeRefreshToken() {
|
||||
return Cookies.remove(RefreshTokenKey)
|
||||
}
|
||||
|
||||
export function getExpiresIn() {
|
||||
return Cookies.get(ExpiresInKey) || -1
|
||||
}
|
||||
|
||||
export function setExpiresIn(time) {
|
||||
return Cookies.set(ExpiresInKey, time)
|
||||
}
|
||||
|
||||
export function removeExpiresIn() {
|
||||
return Cookies.remove(ExpiresInKey)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,203 +1,204 @@
|
|||
<template>
|
||||
<div class="login">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<h3 class="title">若依后台管理系统</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter.native="handleLogin"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter.native="handleLogin"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="medium"
|
||||
type="primary"
|
||||
style="width:100%;"
|
||||
@click.native.prevent="handleLogin"
|
||||
>
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>Copyright © 2018-2021 ruoyi.vip All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCodeImg } from "@/api/login";
|
||||
import Cookies from "js-cookie";
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
codeUrl: "",
|
||||
cookiePassword: "",
|
||||
loginForm: {
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: ""
|
||||
},
|
||||
loginRules: {
|
||||
username: [
|
||||
{ required: true, trigger: "blur", message: "用户名不能为空" }
|
||||
],
|
||||
password: [
|
||||
{ required: true, trigger: "blur", message: "密码不能为空" }
|
||||
],
|
||||
code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
|
||||
},
|
||||
loading: false,
|
||||
redirect: undefined
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function(route) {
|
||||
this.redirect = route.query && route.query.redirect;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCode();
|
||||
this.getCookie();
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.loginForm.uuid = res.uuid;
|
||||
});
|
||||
},
|
||||
getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
const password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get('rememberMe')
|
||||
this.loginForm = {
|
||||
username: username === undefined ? this.loginForm.username : username,
|
||||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.loginForm.rememberMe) {
|
||||
Cookies.set("username", this.loginForm.username, { expires: 30 });
|
||||
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
|
||||
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
|
||||
} else {
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
this.$store.dispatch("Login", this.loginForm).then(() => {
|
||||
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
this.getCode();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss">
|
||||
.login {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
.el-input {
|
||||
height: 38px;
|
||||
input {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.login-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.login-code-img {
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<h3 class="title">若依后台管理系统</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter.native="handleLogin"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter.native="handleLogin"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="medium"
|
||||
type="primary"
|
||||
style="width:100%;"
|
||||
@click.native.prevent="handleLogin"
|
||||
>
|
||||
<span v-if="!loading">登 录</span>
|
||||
<span v-else>登 录 中...</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>Copyright © 2018-2021 ruoyi.vip All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCodeImg } from "@/api/login";
|
||||
import Cookies from "js-cookie";
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
codeUrl: "",
|
||||
cookiePassword: "",
|
||||
loginForm: {
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: ""
|
||||
},
|
||||
loginRules: {
|
||||
username: [
|
||||
{ required: true, trigger: "blur", message: "用户名不能为空" }
|
||||
],
|
||||
password: [
|
||||
{ required: true, trigger: "blur", message: "密码不能为空" }
|
||||
],
|
||||
code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
|
||||
},
|
||||
loading: false,
|
||||
redirect: undefined
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function(route) {
|
||||
this.redirect = route.query && route.query.redirect;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCode();
|
||||
this.getCookie();
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.loginForm.uuid = res.uuid;
|
||||
});
|
||||
},
|
||||
getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
const password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get('rememberMe')
|
||||
this.loginForm = {
|
||||
username: username === undefined ? this.loginForm.username : username,
|
||||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
if (this.loginForm.rememberMe) {
|
||||
Cookies.set("username", this.loginForm.username, { expires: 30 });
|
||||
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
|
||||
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
|
||||
} else {
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
this.$store.dispatch("Login", this.loginForm).then(() => {
|
||||
this.$router.push({ path: this.redirect || "/" }).catch((e)=>{console.log(e);});
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
this.loading = false;
|
||||
this.getCode();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss">
|
||||
.login {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
.el-input {
|
||||
height: 38px;
|
||||
input {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.login-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.login-code-img {
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ spring:
|
|||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
server-addr: 175.25.50.135:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ insert into config_info(id, data_id, group_id, content, md5, gmt_create, gmt_mod
|
|||
(2,'ruoyi-gateway-dev.yml','DEFAULT_GROUP','spring:\r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n cloud:\r\n gateway:\r\n discovery:\r\n locator:\r\n lowerCaseServiceId: true\r\n enabled: true\r\n routes:\r\n # 认证中心\r\n - id: ruoyi-auth\r\n uri: lb://ruoyi-auth\r\n predicates:\r\n - Path=/auth/**\r\n filters:\r\n # 验证码处理\r\n - CacheRequestFilter\r\n - ValidateCodeFilter\r\n - StripPrefix=1\r\n # 代码生成\r\n - id: ruoyi-gen\r\n uri: lb://ruoyi-gen\r\n predicates:\r\n - Path=/code/**\r\n filters:\r\n - StripPrefix=1\r\n # 定时任务\r\n - id: ruoyi-job\r\n uri: lb://ruoyi-job\r\n predicates:\r\n - Path=/schedule/**\r\n filters:\r\n - StripPrefix=1\r\n # 系统模块\r\n - id: ruoyi-system\r\n uri: lb://ruoyi-system\r\n predicates:\r\n - Path=/system/**\r\n filters:\r\n - StripPrefix=1\r\n # 文件服务\r\n - id: ruoyi-file\r\n uri: lb://ruoyi-file\r\n predicates:\r\n - Path=/file/**\r\n filters:\r\n - StripPrefix=1\r\n\r\n# 不校验白名单\r\nignore:\r\n whites:\r\n - /auth/logout\r\n - /auth/login\r\n - /*/v2/api-docs\r\n - /csrf\r\n','ef4a58daf989827334b3aac1c9d68392','2020-05-14 14:17:55','2020-11-18 17:53:23',NULL,'0:0:0:0:0:0:0:1','','','网关模块','null','null','yaml','null'),
|
||||
(3,'ruoyi-auth-dev.yml','DEFAULT_GROUP','spring: \r\n datasource:\r\n driver-class-name: com.mysql.cj.jdbc.Driver\r\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n username: root\r\n password: password\r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n','868c15010a7a15c027d4c90a48aabb3e','2020-11-20 00:00:00','2020-11-20 00:00:00',NULL,'0:0:0:0:0:0:0:1','','','认证中心','null','null','yaml','null'),
|
||||
(4,'ruoyi-monitor-dev.yml','DEFAULT_GROUP','# spring\r\nspring: \r\n security:\r\n user:\r\n name: ruoyi\r\n password: 123456\r\n boot:\r\n admin:\r\n ui:\r\n title: 若依服务状态监控\r\n','d8997d0707a2fd5d9fc4e8409da38129','2020-11-20 00:00:00','2020-12-21 16:28:07',NULL,'0:0:0:0:0:0:0:1','','','监控中心','null','null','yaml','null'),
|
||||
(5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\r\nspring: \r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n datasource:\r\n druid:\r\n stat-view-servlet:\r\n enabled: true\r\n loginUsername: admin\r\n loginPassword: 123456\r\n dynamic:\r\n druid:\r\n initial-size: 5\r\n min-idle: 5\r\n maxActive: 20\r\n maxWait: 60000\r\n timeBetweenEvictionRunsMillis: 60000\r\n minEvictableIdleTimeMillis: 300000\r\n validationQuery: SELECT 1 FROM DUAL\r\n testWhileIdle: true\r\n testOnBorrow: false\r\n testOnReturn: false\r\n poolPreparedStatements: true\r\n maxPoolPreparedStatementPerConnectionSize: 20\r\n filters: stat,wall,slf4j\r\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\r\n datasource:\r\n # 主库数据源\r\n master:\r\n driver-class-name: com.mysql.cj.jdbc.Driver\r\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n username: root\r\n password: password\r\n # 从库数据源\r\n # slave:\r\n # username: \r\n # password: \r\n # url: \r\n # driver-class-name: \r\n # seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭\r\n\r\n# seata配置\r\nseata:\r\n # 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启\r\n enabled: false\r\n # Seata 应用编号,默认为 ${spring.application.name}\r\n application-id: ${spring.application.name}\r\n # Seata 事务组编号,用于 TC 集群名\r\n tx-service-group: ${spring.application.name}-group\r\n # 关闭自动代理\r\n enable-auto-data-source-proxy: false\r\n # 服务配置项\r\n service:\r\n # 虚拟组和分组的映射\r\n vgroup-mapping:\r\n ruoyi-system-group: default\r\n config:\r\n type: nacos\r\n nacos:\r\n serverAddr: 127.0.0.1:8848\r\n group: SEATA_GROUP\r\n namespace:\r\n registry:\r\n type: nacos\r\n nacos:\r\n application: seata-server\r\n server-addr: 127.0.0.1:8848\r\n namespace:\r\n\r\n# mybatis配置\r\nmybatis:\r\n # 搜索指定包别名\r\n typeAliasesPackage: com.ruoyi.system\r\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\r\n mapperLocations: classpath:mapper/**/*.xml\r\n\r\n# swagger配置\r\nswagger:\r\n title: 系统模块接口文档\r\n license: Powered By ruoyi\r\n licenseUrl: https://ruoyi.vip','ac8913dee679e65bb7d482df5f267d4e','2020-11-20 00:00:00','2021-01-27 10:42:25',NULL,'0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','null'),
|
||||
(5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\r\nspring: \r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n datasource:\r\n druid:\r\n stat-view-servlet:\r\n enabled: true\r\n loginUsername: admin\r\n loginPassword: 123456\r\n dynamic:\r\n druid:\r\n initial-size: 5\r\n min-idle: 5\r\n maxActive: 20\r\n maxWait: 60000\r\n timeBetweenEvictionRunsMillis: 60000\r\n minEvictableIdleTimeMillis: 300000\r\n validationQuery: SELECT 1 FROM DUAL\r\n testWhileIdle: true\r\n testOnBorrow: false\r\n testOnReturn: false\r\n poolPreparedStatements: true\r\n maxPoolPreparedStatementPerConnectionSize: 20\r\n filters: stat,wall,slf4j\r\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\r\n datasource:\r\n # 主库数据源\r\n master:\r\n driver-class-name: com.mysql.cj.jdbc.Driver\r\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n username: root\r\n password: password\r\n # 从库数据源\r\n # slave:\r\n # username: \r\n # password: \r\n # url: \r\n # driver-class-name: \r\n # seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭\r\n\r\n# seata配置\r\nseata:\r\n # 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启\r\n enabled: false\r\n # Seata 应用编号,默认为 ${spring.application.name}\r\n application-id: ${spring.application.name}\r\n # Seata 事务组编号,用于 TC 集群名\r\n tx-service-group: ${spring.application.name}-group\r\n # 关闭自动代理\r\n enable-auto-data-source-proxy: false\r\n # 服务配置项\r\n service:\r\n # 虚拟组和分组的映射\r\n vgroup-mapping:\r\n ruoyi-system-group: default\r\n config:\r\n type: nacos\r\n nacos:\r\n serverAddr: 175.25.50.135:8848\r\n group: SEATA_GROUP\r\n namespace:\r\n registry:\r\n type: nacos\r\n nacos:\r\n application: seata-server\r\n server-addr: 175.25.50.135:8848\r\n namespace:\r\n\r\n# mybatis配置\r\nmybatis:\r\n # 搜索指定包别名\r\n typeAliasesPackage: com.ruoyi.system\r\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\r\n mapperLocations: classpath:mapper/**/*.xml\r\n\r\n# swagger配置\r\nswagger:\r\n title: 系统模块接口文档\r\n license: Powered By ruoyi\r\n licenseUrl: https://ruoyi.vip','ac8913dee679e65bb7d482df5f267d4e','2020-11-20 00:00:00','2021-01-27 10:42:25',NULL,'0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','null'),
|
||||
(6,'ruoyi-gen-dev.yml','DEFAULT_GROUP','# spring配置\r\nspring: \r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n datasource: \r\n driver-class-name: com.mysql.cj.jdbc.Driver\r\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n username: root\r\n password: password\r\n\r\n# mybatis配置\r\nmybatis:\r\n # 搜索指定包别名\r\n typeAliasesPackage: com.ruoyi.gen.domain\r\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\r\n mapperLocations: classpath:mapper/**/*.xml\r\n\r\n# swagger配置\r\nswagger:\r\n title: 代码生成接口文档\r\n license: Powered By ruoyi\r\n licenseUrl: https://ruoyi.vip\r\n\r\n# 代码生成\r\ngen: \r\n # 作者\r\n author: ruoyi\r\n # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool\r\n packageName: com.ruoyi.system\r\n # 自动去除表前缀,默认是false\r\n autoRemovePre: false\r\n # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)\r\n tablePrefix: sys_\r\n','8c79f64a4cca9b821a03dc8b27a2d8eb','2020-11-20 00:00:00','2021-01-26 10:36:45',NULL,'0:0:0:0:0:0:0:1','','','代码生成','null','null','yaml','null'),
|
||||
(7,'ruoyi-job-dev.yml','DEFAULT_GROUP','# spring配置\r\nspring: \r\n redis:\r\n host: localhost\r\n port: 6379\r\n password: \r\n datasource:\r\n driver-class-name: com.mysql.cj.jdbc.Driver\r\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n username: root\r\n password: password\r\n\r\n# mybatis配置\r\nmybatis:\r\n # 搜索指定包别名\r\n typeAliasesPackage: com.ruoyi.job.domain\r\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\r\n mapperLocations: classpath:mapper/**/*.xml\r\n\r\n# swagger配置\r\nswagger:\r\n title: 定时任务接口文档\r\n license: Powered By ruoyi\r\n licenseUrl: https://ruoyi.vip\r\n','d6dfade9a2c93c463ae857cd503cb172','2020-11-20 00:00:00','2021-01-26 10:36:04',NULL,'0:0:0:0:0:0:0:1','','','定时任务','null','null','yaml','null'),
|
||||
(8,'ruoyi-file-dev.yml','DEFAULT_GROUP','# 本地文件上传 \r\nfile:\r\n domain: http://127.0.0.1:9300\r\n path: D:/ruoyi/uploadPath\r\n prefix: /statics\r\n\r\n# FastDFS配置\r\nfdfs:\r\n domain: http://8.129.231.12\r\n soTimeout: 3000\r\n connectTimeout: 2000\r\n trackerList: 8.129.231.12:22122\r\n\r\n# Minio配置\r\nminio:\r\n url: http://8.129.231.12:9000\r\n accessKey: minioadmin\r\n secretKey: minioadmin\r\n bucketName: test','5382b93f3d8059d6068c0501fdd41195','2020-11-20 00:00:00','2020-12-21 21:01:59',NULL,'0:0:0:0:0:0:0:1','','','文件服务','null','null','yaml','null'),
|
||||
|
|
|
|||
Loading…
Reference in New Issue