pull/42/head
alikes 5 years ago
parent fff8fb7d86
commit 46eb9a0303

@ -22,6 +22,13 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
</dependency> </dependency>
<!-- spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>

@ -1,5 +1,7 @@
package com.ruoyi.system.api; 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.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; 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.factory.RemoteUserFallbackFactory;
import com.ruoyi.system.api.model.LoginUser; import com.ruoyi.system.api.model.LoginUser;
import java.util.Set;
/** /**
* *
* *
@ -23,5 +27,34 @@ public interface RemoteUserService
* @return * @return
*/ */
@GetMapping(value = "/user/info/{username}") @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; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -8,6 +10,8 @@ import com.ruoyi.system.api.RemoteUserService;
import com.ruoyi.system.api.model.LoginUser; import com.ruoyi.system.api.model.LoginUser;
import feign.hystrix.FallbackFactory; import feign.hystrix.FallbackFactory;
import java.util.Set;
/** /**
* *
* *
@ -25,10 +29,25 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
return new RemoteUserService() return new RemoteUserService()
{ {
@Override @Override
public R<LoginUser> getUserInfo(String username) public R<UserInfo> getUserInfo(String username)
{ {
return R.fail("获取用户失败:" + throwable.getMessage()); 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; package com.ruoyi.system.api.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.Set; import java.util.*;
import java.util.function.Function;
import com.ruoyi.system.api.domain.SysUser; 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 * @author ruoyi
*/ */
public class LoginUser implements Serializable @Slf4j
public class LoginUser implements Serializable, UserDetails,CredentialsContainer
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -21,7 +34,7 @@ public class LoginUser implements Serializable
/** /**
* id * id
*/ */
private Long userid; private Long userId;
/** /**
* *
@ -58,6 +71,63 @@ public class LoginUser implements Serializable
*/ */
private SysUser sysUser; 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() public String getToken()
{ {
return token; return token;
@ -68,16 +138,17 @@ public class LoginUser implements Serializable
this.token = token; 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() public String getUsername()
{ {
return username; return username;
@ -147,4 +218,221 @@ public class LoginUser implements Serializable
{ {
this.sysUser = sysUser; 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
* Oauth2Security WebSecurityConfigResourceServerConfig
*
* @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; package com.ruoyi.auth.controller;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.ruoyi.system.api.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -27,16 +29,16 @@ public class TokenController
@Autowired @Autowired
private SysLoginService sysLoginService; private SysLoginService sysLoginService;
@PostMapping("login") // @PostMapping("login")
public R<?> login(@RequestBody LoginBody form) // public R<?> login(@RequestBody LoginBody form)
{ // {
// 用户登录 // // 用户登录
LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword()); // UserInfo userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
// 获取登录token // // 获取登录token
return R.ok(tokenService.createToken(userInfo)); // return R.ok(tokenService.createToken(userInfo));
} // }
@DeleteMapping("logout") @DeleteMapping("token/logout")
public R<?> logout(HttpServletRequest request) public R<?> logout(HttpServletRequest request)
{ {
LoginUser loginUser = tokenService.getLoginUser(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; package com.ruoyi.auth.service;
import com.ruoyi.system.api.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.Constants; 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.domain.R;
import com.ruoyi.common.core.enums.UserStatus; import com.ruoyi.common.core.enums.UserStatus;
import com.ruoyi.common.core.exception.BaseException; 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.common.core.utils.StringUtils;
import com.ruoyi.system.api.RemoteLogService; import com.ruoyi.system.api.RemoteLogService;
import com.ruoyi.system.api.RemoteUserService; 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)) if (StringUtils.isAnyBlank(username, password))
@ -54,7 +55,7 @@ public class SysLoginService
throw new BaseException("用户名不在指定范围"); throw new BaseException("用户名不在指定范围");
} }
// 查询用户信息 // 查询用户信息
R<LoginUser> userResult = remoteUserService.getUserInfo(username); R<UserInfo> userResult = remoteUserService.getUserInfo(username);
if (R.FAIL == userResult.getCode()) if (R.FAIL == userResult.getCode())
{ {
@ -66,7 +67,7 @@ public class SysLoginService
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
throw new BaseException("登录用户:" + username + " 不存在"); throw new BaseException("登录用户:" + username + " 不存在");
} }
LoginUser userInfo = userResult.getData(); UserInfo userInfo = userResult.getData();
SysUser user = userResult.getData().getSysUser(); SysUser user = userResult.getData().getSysUser();
if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{ {

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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> <artifactId>swagger-annotations</artifactId>
</dependency> </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> </dependencies>
</project> </project>

@ -36,4 +36,14 @@ public class CacheConstants
* *
*/ */
public static final String AUTHORIZATION_HEADER = "authorization"; 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_idclient_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; //package com.ruoyi.common.core.utils;
//
import javax.servlet.http.HttpServletRequest; //import javax.servlet.http.HttpServletRequest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; //import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.ruoyi.common.core.constant.CacheConstants; //import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.text.Convert; //import com.ruoyi.common.core.text.Convert;
//
/** ///**
* // * 权限获取工具类
* // *
* @author ruoyi // * @author ruoyi
*/ // */
public class SecurityUtils //public class SecurityUtils
{ //{
/** // /**
* // * 获取用户
*/ // */
public static String getUsername() // public static String getUsername()
{ // {
String username = ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USERNAME); // String username = ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USERNAME);
return ServletUtils.urlDecode(username); // return ServletUtils.urlDecode(username);
} // }
//
/** // /**
* ID // * 获取用户ID
*/ // */
public static Long getUserId() // public static Long getUserId()
{ // {
return Convert.toLong(ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USER_ID)); // return Convert.toLong(ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USER_ID));
} // }
//
/** // /**
* token // * 获取请求token
*/ // */
public static String getToken() // public static String getToken()
{ // {
return getToken(ServletUtils.getRequest()); // return getToken(ServletUtils.getRequest());
} // }
//
/** // /**
* requesttoken // * 根据request获取请求token
*/ // */
public static String getToken(HttpServletRequest request) // public static String getToken(HttpServletRequest request)
{ // {
String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER); // String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER);
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX)) // if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
{ // {
token = token.replace(CacheConstants.TOKEN_PREFIX, ""); // token = token.replace(CacheConstants.TOKEN_PREFIX, "");
} // }
return token; // return token;
} // }
//
/** // /**
* // * 是否为管理员
* // *
* @param userId ID // * @param userId 用户ID
* @return // * @return 结果
*/ // */
public static boolean isAdmin(Long userId) // public static boolean isAdmin(Long userId)
{ // {
return userId != null && 1L == userId; // return userId != null && 1L == userId;
} // }
//
/** // /**
* BCryptPasswordEncoder // * 生成BCryptPasswordEncoder密码
* // *
* @param password // * @param password 密码
* @return // * @return 加密字符串
*/ // */
public static String encryptPassword(String password) // public static String encryptPassword(String password)
{ // {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password); // return passwordEncoder.encode(password);
} // }
//
/** // /**
* // * 判断密码是否相同
* // *
* @param rawPassword // * @param rawPassword 真实密码
* @param encodedPassword // * @param encodedPassword 加密后字符
* @return // * @return 结果
*/ // */
public static boolean matchesPassword(String rawPassword, String encodedPassword) // public static boolean matchesPassword(String rawPassword, String encodedPassword)
{ // {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword); // return passwordEncoder.matches(rawPassword, encodedPassword);
} // }
} //
//
//
//}

@ -6,6 +6,8 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.security.utils.SecurityUtils;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature; import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterReturning;
@ -20,7 +22,6 @@ import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSON; 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.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.core.utils.ip.IpUtils;

@ -15,7 +15,13 @@
</description> </description>
<dependencies> <dependencies>
<!-- Spring Security Oauth2 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!-- RuoYi Api System --> <!-- RuoYi Api System -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>

@ -6,12 +6,14 @@ import java.lang.annotation.Inherited;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 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.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import com.ruoyi.common.security.config.ApplicationConfig; import com.ruoyi.common.security.config.ApplicationConfig;
import com.ruoyi.common.security.feign.FeignAutoConfiguration;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ -24,8 +26,7 @@ import com.ruoyi.common.security.feign.FeignAutoConfiguration;
// 开启线程异步执行 // 开启线程异步执行
@EnableAsync @EnableAsync
// 自动加载类 // 自动加载类
@Import({ ApplicationConfig.class, FeignAutoConfiguration.class }) @Import({ ApplicationConfig.class, FeignConfig.class , SecurityImportBeanDefinitionRegistrar.class})
public @interface EnableCustomConfig public @interface EnableCustomConfig {
{
} }

@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.PatternMatchUtils; import org.springframework.util.PatternMatchUtils;
@ -111,11 +112,11 @@ public class PreAuthorizeAspect
public boolean hasPermi(String permission) public boolean hasPermi(String permission)
{ {
LoginUser userInfo = tokenService.getLoginUser(); LoginUser userInfo = tokenService.getLoginUser();
if (StringUtils.isEmpty(userInfo) || CollectionUtils.isEmpty(userInfo.getPermissions())) if (StringUtils.isEmpty(userInfo) || CollectionUtils.isEmpty(userInfo.getAuthorities()))
{ {
return false; return false;
} }
return hasPermissions(userInfo.getPermissions(), permission); return hasPermissions(userInfo.getAuthorities(), permission);
} }
/** /**
@ -142,7 +143,7 @@ public class PreAuthorizeAspect
{ {
return false; return false;
} }
Collection<String> authorities = userInfo.getPermissions(); Collection<GrantedAuthority> authorities = userInfo.getAuthorities();
for (String permission : permissions) for (String permission : permissions)
{ {
if (permission != null && hasPermissions(authorities, permission)) if (permission != null && hasPermissions(authorities, permission))
@ -217,9 +218,8 @@ public class PreAuthorizeAspect
* @param permission * @param permission
* @return * @return
*/ */
private boolean hasPermissions(Collection<String> authorities, String permission) private boolean hasPermissions(Collection<GrantedAuthority> authorities, String permission)
{ {
return authorities.stream().filter(StringUtils::hasText) return authorities.stream().filter(grantedAuthority-> {return StringUtils.hasText(grantedAuthority.getAuthority());}).anyMatch(grantedAuthority -> ALL_PERMISSION.contains(grantedAuthority.getAuthority()) || PatternMatchUtils.simpleMatch(permission, grantedAuthority.getAuthority()));
.anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(permission, x));
} }
} }

@ -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; //package com.ruoyi.common.security.feign;
//
import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; //import org.springframework.context.annotation.Configuration;
import feign.RequestInterceptor; //import feign.RequestInterceptor;
//
/** ///**
* Feign // * Feign 配置注册
* // *
* @author ruoyi // * @author ruoyi
**/ // **/
@Configuration //@Configuration
public class FeignAutoConfiguration //public class FeignAutoConfiguration
{ //{
@Bean // @Bean
public RequestInterceptor requestInterceptor() // public RequestInterceptor requestInterceptor()
{ // {
return new FeignRequestInterceptor(); // 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; //package com.ruoyi.common.security.feign;
//
import java.util.Map; //import java.util.Map;
import javax.servlet.http.HttpServletRequest; //import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.CacheConstants; //import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.utils.ServletUtils; //import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; //import com.ruoyi.common.core.utils.StringUtils;
import feign.RequestInterceptor; //import feign.RequestInterceptor;
import feign.RequestTemplate; //import feign.RequestTemplate;
//
/** ///**
* feign // * feign 请求拦截器
* // *
* @author ruoyi // * @author ruoyi
*/ // */
@Component //@Component
public class FeignRequestInterceptor implements RequestInterceptor //public class FeignRequestInterceptor implements RequestInterceptor
{ //{
@Override // @Override
public void apply(RequestTemplate requestTemplate) // public void apply(RequestTemplate requestTemplate)
{ // {
HttpServletRequest httpServletRequest = ServletUtils.getRequest(); // HttpServletRequest httpServletRequest = ServletUtils.getRequest();
if (StringUtils.isNotNull(httpServletRequest)) // if (StringUtils.isNotNull(httpServletRequest))
{ // {
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest); // Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
// 传递用户信息请求头,防止丢失 // // 传递用户信息请求头,防止丢失
String userId = headers.get(CacheConstants.DETAILS_USER_ID); // String userId = headers.get(CacheConstants.DETAILS_USER_ID);
if (StringUtils.isNotEmpty(userId)) // if (StringUtils.isNotEmpty(userId))
{ // {
requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId); // requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId);
} // }
String userName = headers.get(CacheConstants.DETAILS_USERNAME); // String userName = headers.get(CacheConstants.DETAILS_USERNAME);
if (StringUtils.isNotEmpty(userName)) // if (StringUtils.isNotEmpty(userName))
{ // {
requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName); // requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName);
} // }
String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER); // String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER);
if (StringUtils.isNotEmpty(authentication)) // if (StringUtils.isNotEmpty(authentication))
{ // {
requestTemplate.header(CacheConstants.AUTHORIZATION_HEADER, 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.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.security.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.utils.IdUtils; 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.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.core.utils.ip.IpUtils;
@ -41,7 +42,7 @@ public class TokenService
// 生成token // 生成token
String token = IdUtils.fastUUID(); String token = IdUtils.fastUUID();
loginUser.setToken(token); loginUser.setToken(token);
loginUser.setUserid(loginUser.getSysUser().getUserId()); loginUser.setUserId(loginUser.getSysUser().getUserId());
loginUser.setUsername(loginUser.getSysUser().getUserName()); loginUser.setUsername(loginUser.getSysUser().getUserName());
loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest())); loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
refreshToken(loginUser); refreshToken(loginUser);
@ -71,15 +72,17 @@ public class TokenService
*/ */
public LoginUser getLoginUser(HttpServletRequest request) public LoginUser getLoginUser(HttpServletRequest request)
{ {
// 获取请求携带的令牌 // // 获取请求携带的令牌
String token = SecurityUtils.getToken(request); // String token = SecurityUtils.getToken(request);
if (StringUtils.isNotEmpty(token)) // if (StringUtils.isNotEmpty(token))
{ // {
String userKey = getTokenKey(token); // String userKey = getTokenKey(token);
LoginUser user = redisService.getCacheObject(userKey); // LoginUser user = redisService.getCacheObject(userKey);
return user; // LoginUser user = SecurityUtils.getLoginUser();
} //
return null; // }
// 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.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo; import springfox.documentation.service.*;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.spring.web.plugins.Docket;
@ -96,9 +92,20 @@ public class SwaggerAutoConfiguration
.securityReferences(defaultAuth()) .securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$")) .forPaths(PathSelectors.regex("^(?!auth).*$"))
.build()); .build());
securityContexts.add(SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
.build());
return securityContexts; 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; 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) private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
{ {
return new ApiInfoBuilder() return new ApiInfoBuilder()

@ -1,125 +1,125 @@
package com.ruoyi.gateway.filter; //package com.ruoyi.gateway.filter;
//
import javax.annotation.Resource; //import javax.annotation.Resource;
import org.slf4j.Logger; //import org.slf4j.Logger;
import org.slf4j.LoggerFactory; //import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; //import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter; //import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered; //import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory; //import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.ValueOperations; //import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpStatus; //import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; //import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest; //import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; //import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; //import org.springframework.web.server.ServerWebExchange;
import com.alibaba.fastjson.JSON; //import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; //import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.constant.CacheConstants; //import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.constant.Constants; //import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.domain.R; //import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.ServletUtils; //import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; //import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.redis.service.RedisService; //import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties; //import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
import reactor.core.publisher.Mono; //import reactor.core.publisher.Mono;
//
/** ///**
* // * 网关鉴权
* // *
* @author ruoyi // * @author ruoyi
*/ // */
@Component //@Component
public class AuthFilter implements GlobalFilter, Ordered //public class AuthFilter implements GlobalFilter, Ordered
{ //{
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); // private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
//
private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60; // private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
//
// 排除过滤的 uri 地址nacos自行添加 // // 排除过滤的 uri 地址nacos自行添加
@Autowired // @Autowired
private IgnoreWhiteProperties ignoreWhite; // private IgnoreWhiteProperties ignoreWhite;
//
@Resource(name = "stringRedisTemplate") // @Resource(name = "stringRedisTemplate")
private ValueOperations<String, String> sops; // private ValueOperations<String, String> sops;
//
@Autowired // @Autowired
private RedisService redisService; // private RedisService redisService;
//
@Override // @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) // public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{ // {
String url = exchange.getRequest().getURI().getPath(); // String url = exchange.getRequest().getURI().getPath();
// 跳过不需要验证的路径 // // 跳过不需要验证的路径
if (StringUtils.matches(url, ignoreWhite.getWhites())) // if (StringUtils.matches(url, ignoreWhite.getWhites()))
{ // {
return chain.filter(exchange); // return chain.filter(exchange);
} // }
String token = getToken(exchange.getRequest()); // String token = getToken(exchange.getRequest());
if (StringUtils.isBlank(token)) // if (StringUtils.isBlank(token))
{ // {
return setUnauthorizedResponse(exchange, "令牌不能为空"); // return setUnauthorizedResponse(exchange, "令牌不能为空");
} // }
String userStr = sops.get(getTokenKey(token)); // String userStr = sops.get(getTokenKey(token));
if (StringUtils.isNull(userStr)) // if (StringUtils.isNull(userStr))
{ // {
return setUnauthorizedResponse(exchange, "登录状态已过期"); // return setUnauthorizedResponse(exchange, "登录状态已过期");
} // }
JSONObject obj = JSONObject.parseObject(userStr); // JSONObject obj = JSONObject.parseObject(userStr);
String userid = obj.getString("userid"); // String userid = obj.getString("userid");
String username = obj.getString("username"); // String username = obj.getString("username");
if (StringUtils.isBlank(userid) || StringUtils.isBlank(username)) // if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
{ // {
return setUnauthorizedResponse(exchange, "令牌验证失败"); // return setUnauthorizedResponse(exchange, "令牌验证失败");
} // }
//
// 设置过期时间 // // 设置过期时间
redisService.expire(getTokenKey(token), EXPIRE_TIME); // redisService.expire(getTokenKey(token), EXPIRE_TIME);
// 设置用户信息到请求 // // 设置用户信息到请求
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid) // ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid)
.header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build(); // .header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build(); // ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
//
return chain.filter(mutableExchange); // return chain.filter(mutableExchange);
} // }
//
private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg) // private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
{ // {
ServerHttpResponse response = exchange.getResponse(); // ServerHttpResponse response = exchange.getResponse();
response.getHeaders().setContentType(MediaType.APPLICATION_JSON); // response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setStatusCode(HttpStatus.OK); // response.setStatusCode(HttpStatus.OK);
//
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath()); // log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
//
return response.writeWith(Mono.fromSupplier(() -> { // return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory(); // DataBufferFactory bufferFactory = response.bufferFactory();
return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg))); // return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
})); // }));
} // }
//
private String getTokenKey(String token) // private String getTokenKey(String token)
{ // {
return CacheConstants.LOGIN_TOKEN_KEY + token; // return CacheConstants.LOGIN_TOKEN_KEY + token;
} // }
//
/** // /**
* token // * 获取请求token
*/ // */
private String getToken(ServerHttpRequest request) // private String getToken(ServerHttpRequest request)
{ // {
String token = request.getHeaders().getFirst(CacheConstants.HEADER); // String token = request.getHeaders().getFirst(CacheConstants.HEADER);
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX)) // if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
{ // {
token = token.replace(CacheConstants.TOKEN_PREFIX, ""); // token = token.replace(CacheConstants.TOKEN_PREFIX, "");
} // }
return token; // return token;
} // }
//
@Override // @Override
public int getOrder() // public int getOrder()
{ // {
return -200; // return -200;
} // }
} //}

@ -16,14 +16,15 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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: sentinel:
# 取消控制台懒加载 # 取消控制台懒加载
eager: true eager: true
@ -34,7 +35,7 @@ spring:
datasource: datasource:
ds1: ds1:
nacos: nacos:
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
dataId: sentinel-ruoyi-gateway dataId: sentinel-ruoyi-gateway
groupId: DEFAULT_GROUP groupId: DEFAULT_GROUP
data-type: json data-type: json

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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.constant.GenConstants;
import com.ruoyi.common.core.exception.CustomException; import com.ruoyi.common.core.exception.CustomException;
import com.ruoyi.common.core.text.CharsetKit; 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.StringUtils;
import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.common.core.utils.file.FileUtils;
import com.ruoyi.gen.domain.GenTable; import com.ruoyi.gen.domain.GenTable;

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.exception.job.TaskException; 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.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.domain.AjaxResult;

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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> </properties>
<dependencies> <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> <dependency>
<groupId>com.alibaba.csp</groupId> <groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId> <artifactId>sentinel-core</artifactId>
@ -145,6 +172,10 @@
<version>1.16.1</version> <version>1.16.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>com.ruoyi</groupId>-->
<!-- <artifactId>ruoyi-common-security</artifactId>-->
<!-- </dependency>-->
</dependencies> </dependencies>
<build> <build>

@ -17,15 +17,20 @@ package com.alibaba.csp.sentinel.dashboard;
import com.alibaba.csp.sentinel.init.InitExecutor; 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.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/** /**
* Sentinel dashboard application. * Sentinel dashboard application.
* *
* @author Carpenter Lee * @author Carpenter Lee
*/ */
@SpringBootApplication //@EnableCustomConfig
//@EnableRyFeignClients
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class RuoYiSentinelDashboardApplication { public class RuoYiSentinelDashboardApplication {
public static void main(String[] args) { public static void main(String[] args) {

@ -47,8 +47,8 @@ public class WebConfig implements WebMvcConfigurer {
private final Logger logger = LoggerFactory.getLogger(WebConfig.class); private final Logger logger = LoggerFactory.getLogger(WebConfig.class);
@Autowired // @Autowired
private LoginAuthenticationFilter loginAuthenticationFilter; // private LoginAuthenticationFilter loginAuthenticationFilter;
@Autowired @Autowired
private AuthorizationInterceptor authorizationInterceptor; private AuthorizationInterceptor authorizationInterceptor;
@ -104,13 +104,13 @@ public class WebConfig implements WebMvcConfigurer {
}); });
} }
@Bean // @Bean
public FilterRegistrationBean authenticationFilterRegistration() { // public FilterRegistrationBean authenticationFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); // FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(loginAuthenticationFilter); // registration.setFilter(loginAuthenticationFilter);
registration.addUrlPatterns("/*"); // registration.addUrlPatterns("/*");
registration.setName("authenticationFilter"); // registration.setName("authenticationFilter");
registration.setOrder(0); // registration.setOrder(0);
return registration; // 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 java.util.List;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; 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.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.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; 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.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 com.alibaba.csp.sentinel.dashboard.domain.Result;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -51,7 +50,7 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping(value = "/v2/flow") @RequestMapping(value = "/v2/flow")
public class FlowControllerV2 { public class FlowControllerV2 extends BaseController {
private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class); 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; 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.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -36,7 +37,7 @@ import java.util.Properties;
@Configuration @Configuration
public class NacosConfig { public class NacosConfig {
@Value("${spring.nacos.server-addr}") @Value("${spring.cloud.nacos.config.server-addr}")
private String serverAddr; private String serverAddr;
@Bean @Bean
@ -49,6 +50,16 @@ public class NacosConfig {
return s -> JSON.parseArray(s, FlowRuleEntity.class); 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 @Bean
public ConfigService nacosConfigService() throws Exception { public ConfigService nacosConfigService() throws Exception {
if(StringUtils.isEmpty(serverAddr)){//不配置时,使用默认配置 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>&nbsp;&nbsp;新增降级规则</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 -->

@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.StringUtils;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.domain.AjaxResult;

@ -4,6 +4,8 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.security.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping; 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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 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.StringUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; 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 org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.StringUtils;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; 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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 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.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; 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.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.R; 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.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.controller.BaseController; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.domain.AjaxResult;

@ -5,7 +5,11 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; 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.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; 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 org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.domain.R; 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.StringUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
@ -101,7 +104,7 @@ public class SysUserController extends BaseController
* *
*/ */
@GetMapping("/info/{username}") @GetMapping("/info/{username}")
public R<LoginUser> info(@PathVariable("username") String username) public R<UserInfo> info(@PathVariable("username") String username)
{ {
SysUser sysUser = userService.selectUserByUserName(username); SysUser sysUser = userService.selectUserByUserName(username);
if (StringUtils.isNull(sysUser)) if (StringUtils.isNull(sysUser))
@ -112,7 +115,7 @@ public class SysUserController extends BaseController
Set<String> roles = permissionService.getRolePermission(sysUser.getUserId()); Set<String> roles = permissionService.getRolePermission(sysUser.getUserId());
// 权限集合 // 权限集合
Set<String> permissions = permissionService.getMenuPermission(sysUser.getUserId()); Set<String> permissions = permissionService.getMenuPermission(sysUser.getUserId());
LoginUser sysUserVo = new LoginUser(); UserInfo sysUserVo = new UserInfo();
sysUserVo.setSysUser(sysUser); sysUserVo.setSysUser(sysUser);
sysUserVo.setRoles(roles); sysUserVo.setRoles(roles);
sysUserVo.setPermissions(permissions); sysUserVo.setPermissions(permissions);

@ -11,7 +11,7 @@ import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.common.core.constant.UserConstants; 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.utils.StringUtils;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.domain.SysUser;

@ -9,7 +9,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.exception.CustomException; 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.core.utils.StringUtils;
import com.ruoyi.common.datascope.annotation.DataScope; import com.ruoyi.common.datascope.annotation.DataScope;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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' import request from '@/utils/request'
const client_id = 'web' const client_id = 'web'
const client_secret = '123456' const client_secret = '123456'
const scope = 'server' const scope = 'server'
// 登录方法 // // 登录方法
export function login(username, password, code, uuid) { // export function login(username, password, code, uuid) {
return request({ // return request({
url: '/auth/login', // url: '/auth/login',
method: 'post', // method: 'post',
data: { username, password, code, uuid } // data: { username, password, code, uuid }
}) // })
} // }
//
// 刷新方法 // // 刷新方法
export function refreshToken() { // export function refreshToken() {
return request({ // return request({
url: '/auth/refresh', // url: '/auth/refresh',
method: 'post' // method: 'post'
}) // })
} // }
//
// 获取用户详细信息 // // 获取用户详细信息
export function getInfo() { // export function getInfo() {
return request({ // return request({
url: '/system/user/getInfo', // url: '/system/user/getInfo',
method: 'get' // method: 'get'
}) // })
} // }
//
// 退出方法 // // 退出方法
export function logout() { // export function logout() {
return request({ // return request({
url: '/auth/logout', // url: '/auth/logout',
method: 'delete' // method: 'delete'
}) // })
} // }
//
// 获取验证码 // // 获取验证码
export function getCodeImg() { // export function getCodeImg() {
return request({ // return request({
url: '/code', // url: '/code',
method: 'get' // 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 { login, logout, getInfo, refreshToken } from '@/api/login'
import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth' import { getToken, setToken,getRefreshToken, setRefreshToken, setExpiresIn, removeToken } from '@/utils/auth'
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
name: '', refresh_token: getRefreshToken(),
avatar: '', name: '',
roles: [], avatar: '',
permissions: [] roles: [],
}, permissions: []
},
mutations: {
SET_TOKEN: (state, token) => { mutations: {
state.token = token SET_TOKEN: (state, token) => {
}, state.token = token
SET_EXPIRES_IN: (state, time) => { },
state.expires_in = time SET_EXPIRES_IN: (state, time) => {
}, state.expires_in = time
SET_NAME: (state, name) => { },
state.name = name SET_REFRESH_TOKEN: (state, token) => {
}, state.refresh_token = token
SET_AVATAR: (state, avatar) => { },
state.avatar = avatar SET_NAME: (state, name) => {
}, state.name = name
SET_ROLES: (state, roles) => { },
state.roles = roles SET_AVATAR: (state, avatar) => {
}, state.avatar = avatar
SET_PERMISSIONS: (state, permissions) => { },
state.permissions = permissions SET_ROLES: (state, roles) => {
} state.roles = roles
}, },
SET_PERMISSIONS: (state, permissions) => {
actions: { state.permissions = permissions
// 登录 }
Login({ commit }, userInfo) { },
const username = userInfo.username.trim()
const password = userInfo.password actions: {
const code = userInfo.code // // 登录
const uuid = userInfo.uuid // Login({ commit }, userInfo) {
return new Promise((resolve, reject) => { // const username = userInfo.username.trim()
login(username, password, code, uuid).then(res => { // const password = userInfo.password
let data = res.data // const code = userInfo.code
setToken(data.access_token) // const uuid = userInfo.uuid
commit('SET_TOKEN', data.access_token) // return new Promise((resolve, reject) => {
setExpiresIn(data.expires_in) // login(username, password, code, uuid).then(res => {
commit('SET_EXPIRES_IN', data.expires_in) // let data = res.data
resolve() // setToken(data.access_token)
}).catch(error => { // commit('SET_TOKEN', data.access_token)
reject(error) // 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 Login({ commit }, userInfo) {
const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : user.avatar; const username = userInfo.username.trim()
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 const password = userInfo.password
commit('SET_ROLES', res.roles) const code = userInfo.code
commit('SET_PERMISSIONS', res.permissions) const uuid = userInfo.uuid
} else { return new Promise((resolve, reject) => {
commit('SET_ROLES', ['ROLE_DEFAULT']) login(username, password, code, uuid).then(res => {
} setToken(res.access_token)
commit('SET_NAME', user.userName) commit('SET_TOKEN', res.access_token)
commit('SET_AVATAR', avatar) setRefreshToken(res.refresh_token)
resolve(res) commit('SET_REFRESH_TOKEN', res.refresh_token)
}).catch(error => { setExpiresIn(res.expires_in)
reject(error) commit('SET_EXPIRES_IN', res.expires_in)
}) resolve()
}) }).catch(error => {
}, reject(error)
})
// 刷新token })
RefreshToken({commit, state}) { },
return new Promise((resolve, reject) => {
refreshToken(state.token).then(res => { // 获取用户信息
setExpiresIn(res.data) GetInfo({ commit, state }) {
commit('SET_EXPIRES_IN', res.data) return new Promise((resolve, reject) => {
resolve() getInfo(state.token).then(res => {
}).catch(error => { const user = res.user
reject(error) 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'])
LogOut({ commit, state }) { }
return new Promise((resolve, reject) => { commit('SET_NAME', user.userName)
logout(state.token).then(() => { commit('SET_AVATAR', avatar)
commit('SET_TOKEN', '') resolve(res)
commit('SET_ROLES', []) }).catch(error => {
commit('SET_PERMISSIONS', []) reject(error)
removeToken() })
resolve() })
}).catch(error => { },
reject(error)
}) // // 刷新token
}) // RefreshToken({commit, state}) {
}, // return new Promise((resolve, reject) => {
// refreshToken(state.token).then(res => {
// 前端 登出 // setExpiresIn(res.data)
FedLogOut({ commit }) { // commit('SET_EXPIRES_IN', res.data)
return new Promise(resolve => { // resolve()
commit('SET_TOKEN', '') // }).catch(error => {
removeToken() // reject(error)
resolve() // })
}) // })
} // },
}
} // 刷新token
RefreshToken({commit, state}) {
export default user 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' import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token' const TokenKey = 'Admin-Token'
const RefreshTokenKey = 'Admin-Refresh-Token'
const ExpiresInKey = 'Admin-Expires-In' const ExpiresInKey = 'Admin-Expires-In'
export function getToken() { export function getToken() {
return Cookies.get(TokenKey) return Cookies.get(TokenKey)
} }
export function setToken(token) { export function setToken(token) {
return Cookies.set(TokenKey, token) return Cookies.set(TokenKey, token)
} }
export function removeToken() { export function removeToken() {
return Cookies.remove(TokenKey) return Cookies.remove(TokenKey)
} }
export function getExpiresIn() { export function getRefreshToken() {
return Cookies.get(ExpiresInKey) || -1 return Cookies.get(RefreshTokenKey) || ``
} }
export function setExpiresIn(time) { export function setRefreshToken(token) {
return Cookies.set(ExpiresInKey, time) return Cookies.set(RefreshTokenKey, token)
} }
export function removeExpiresIn() { export function removeRefreshToken() {
return Cookies.remove(ExpiresInKey) 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> <template>
<div class="login"> <div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">若依后台管理系统</h3> <h3 class="title">若依后台管理系统</h3>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> <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" /> <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input
v-model="loginForm.password" v-model="loginForm.password"
type="password" type="password"
auto-complete="off" auto-complete="off"
placeholder="密码" placeholder="密码"
@keyup.enter.native="handleLogin" @keyup.enter.native="handleLogin"
> >
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="code"> <el-form-item prop="code">
<el-input <el-input
v-model="loginForm.code" v-model="loginForm.code"
auto-complete="off" auto-complete="off"
placeholder="验证码" placeholder="验证码"
style="width: 63%" style="width: 63%"
@keyup.enter.native="handleLogin" @keyup.enter.native="handleLogin"
> >
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input> </el-input>
<div class="login-code"> <div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/> <img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div> </div>
</el-form-item> </el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"></el-checkbox> <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"></el-checkbox>
<el-form-item style="width:100%;"> <el-form-item style="width:100%;">
<el-button <el-button
:loading="loading" :loading="loading"
size="medium" size="medium"
type="primary" type="primary"
style="width:100%;" style="width:100%;"
@click.native.prevent="handleLogin" @click.native.prevent="handleLogin"
> >
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
<span v-else> ...</span> <span v-else> ...</span>
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span>Copyright © 2018-2021 ruoyi.vip All Rights Reserved.</span> <span>Copyright © 2018-2021 ruoyi.vip All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { getCodeImg } from "@/api/login"; import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt' import { encrypt, decrypt } from '@/utils/jsencrypt'
export default { export default {
name: "Login", name: "Login",
data() { data() {
return { return {
codeUrl: "", codeUrl: "",
cookiePassword: "", cookiePassword: "",
loginForm: { loginForm: {
username: "admin", username: "admin",
password: "admin123", password: "admin123",
rememberMe: false, rememberMe: false,
code: "", code: "",
uuid: "" uuid: ""
}, },
loginRules: { loginRules: {
username: [ username: [
{ required: true, trigger: "blur", message: "用户名不能为空" } { required: true, trigger: "blur", message: "用户名不能为空" }
], ],
password: [ password: [
{ required: true, trigger: "blur", message: "密码不能为空" } { required: true, trigger: "blur", message: "密码不能为空" }
], ],
code: [{ required: true, trigger: "change", message: "验证码不能为空" }] code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
}, },
loading: false, loading: false,
redirect: undefined redirect: undefined
}; };
}, },
watch: { watch: {
$route: { $route: {
handler: function(route) { handler: function(route) {
this.redirect = route.query && route.query.redirect; this.redirect = route.query && route.query.redirect;
}, },
immediate: true immediate: true
} }
}, },
created() { created() {
this.getCode(); this.getCode();
this.getCookie(); this.getCookie();
}, },
methods: { methods: {
getCode() { getCode() {
getCodeImg().then(res => { getCodeImg().then(res => {
this.codeUrl = "data:image/gif;base64," + res.img; this.codeUrl = "data:image/gif;base64," + res.img;
this.loginForm.uuid = res.uuid; this.loginForm.uuid = res.uuid;
}); });
}, },
getCookie() { getCookie() {
const username = Cookies.get("username"); const username = Cookies.get("username");
const password = Cookies.get("password"); const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe') const rememberMe = Cookies.get('rememberMe')
this.loginForm = { this.loginForm = {
username: username === undefined ? this.loginForm.username : username, username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password), password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}; };
}, },
handleLogin() { handleLogin() {
this.$refs.loginForm.validate(valid => { this.$refs.loginForm.validate(valid => {
if (valid) { if (valid) {
this.loading = true; this.loading = true;
if (this.loginForm.rememberMe) { if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 }); Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 }); Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 }); Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else { } else {
Cookies.remove("username"); Cookies.remove("username");
Cookies.remove("password"); Cookies.remove("password");
Cookies.remove('rememberMe'); Cookies.remove('rememberMe');
} }
this.$store.dispatch("Login", this.loginForm).then(() => { this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{}); this.$router.push({ path: this.redirect || "/" }).catch((e)=>{console.log(e);});
}).catch(() => { }).catch((e) => {
this.loading = false; console.log(e);
this.getCode(); this.loading = false;
}); this.getCode();
} });
}); }
} });
} }
}; }
</script> };
</script>
<style rel="stylesheet/scss" lang="scss">
.login { <style rel="stylesheet/scss" lang="scss">
display: flex; .login {
justify-content: center; display: flex;
align-items: center; justify-content: center;
height: 100%; align-items: center;
background-image: url("../assets/images/login-background.jpg"); height: 100%;
background-size: cover; background-image: url("../assets/images/login-background.jpg");
} background-size: cover;
.title { }
margin: 0px auto 30px auto; .title {
text-align: center; margin: 0px auto 30px auto;
color: #707070; text-align: center;
} color: #707070;
}
.login-form {
border-radius: 6px; .login-form {
background: #ffffff; border-radius: 6px;
width: 400px; background: #ffffff;
padding: 25px 25px 5px 25px; width: 400px;
.el-input { padding: 25px 25px 5px 25px;
height: 38px; .el-input {
input { height: 38px;
height: 38px; input {
} height: 38px;
} }
.input-icon { }
height: 39px; .input-icon {
width: 14px; height: 39px;
margin-left: 2px; width: 14px;
} margin-left: 2px;
} }
.login-tip { }
font-size: 13px; .login-tip {
text-align: center; font-size: 13px;
color: #bfbfbf; text-align: center;
} color: #bfbfbf;
.login-code { }
width: 33%; .login-code {
height: 38px; width: 33%;
float: right; height: 38px;
img { float: right;
cursor: pointer; img {
vertical-align: middle; cursor: pointer;
} vertical-align: middle;
} }
.el-login-footer { }
height: 40px; .el-login-footer {
line-height: 40px; height: 40px;
position: fixed; line-height: 40px;
bottom: 0; position: fixed;
width: 100%; bottom: 0;
text-align: center; width: 100%;
color: #fff; text-align: center;
font-family: Arial; color: #fff;
font-size: 12px; font-family: Arial;
letter-spacing: 1px; font-size: 12px;
} letter-spacing: 1px;
.login-code-img { }
height: 38px; .login-code-img {
} height: 38px;
</style> }
</style>

@ -14,11 +14,12 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: 127.0.0.1:8848 server-addr: 175.25.50.135:8848
# 配置文件格式 # 配置文件格式
file-extension: yml 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'), (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'), (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'), (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'), (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'), (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'), (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…
Cancel
Save