Commit 5bccab74 authored by ZBoHang's avatar ZBoHang

🎉 tada

parents
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.greatchn</groupId>
<artifactId>security_oauth_single_login</artifactId>
<version>1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>authorization_server</artifactId>
<version>1.0.1</version>
<name>authorization_server</name>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</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>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
package com.greatchn.authorization_server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AuthorizationServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApplication.class, args);
}
}
package com.greatchn.authorization_server.config;
import com.greatchn.authorization_server.constant.Constant;
import com.greatchn.authorization_server.handler.AccessTokenConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* @CustomAuthorizationServerConfig: 授权服务 config
* @author: ZBoHang
* @time: 2023/2/27 13:29
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Resource
private DataSource dataSource;
@Resource
private AccessTokenConverter accessTokenConverter;
/**
* 配置安全约束
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// 放开 /oauth/check 端点 供资源服务器校验token的合法性
security.passwordEncoder(NoOpPasswordEncoder.getInstance())
.checkTokenAccess("permitAll()")
.tokenKeyAccess("permitAll()")
.allowFormAuthenticationForClients();
}
/**
* 配置客户端
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(jdbcClientDetailsService()).build();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// 配置token的管理
.tokenServices(tokenServices())
.accessTokenConverter(jwtAccessTokenConverter())
// 默认POST 指定GET方便测试
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
/**
* 配置令牌管理服务
* @return
*/
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
// 配置客户端详情服务,获取客户端的信息
services.setClientDetailsService(new JdbcClientDetailsService(this.dataSource));
// 支持刷新令牌
services.setSupportRefreshToken(true);
// 配置令牌的存储方式,此时采用内存方式存储
services.setTokenStore(tokenStore());
// 访问令牌有效时间2小时
services.setAccessTokenValiditySeconds(7200);
// 刷新令牌的有效时间3天
services.setRefreshTokenValiditySeconds(259200);
// JWT token 增强 ##(JWT token 时配置)
services.setTokenEnhancer(jwtAccessTokenConverter());
return services;
}
/**
* 令牌管理
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* JWT 令牌存储转化
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(Constant.JWT_SECRET_KEY);
// 设置token转化
jwtAccessTokenConverter.setAccessTokenConverter(this.accessTokenConverter);
return jwtAccessTokenConverter;
}
/**
* 客户端信息
*/
@Bean
public JdbcClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(this.dataSource);
}
}
package com.greatchn.authorization_server.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis 配置类
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
@SuppressWarnings("rawtypes")
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());
// 开启事务
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
}
package com.greatchn.authorization_server.config;
import com.greatchn.authorization_server.filter.ExceptionFilter;
import com.greatchn.authorization_server.filter.TokenFilter;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @AuthTokenConfig:
* @author: ZBoHang
* @time: 2023/2/8 13:45
*/
@Component("securityFilterConfig")
public class SecurityFilterConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
@Resource
private ExceptionFilter exceptionFilter;
@Resource
private TokenFilter tokenFilter;
@Override
public void configure(HttpSecurity builder) {
builder
.addFilterBefore(this.tokenFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(this.exceptionFilter, TokenFilter.class);
}
}
package com.greatchn.authorization_server.config;
import com.greatchn.authorization_server.handler.AccDecisionHandler;
import com.greatchn.authorization_server.handler.AccDeniedHandler;
import com.greatchn.authorization_server.handler.AuthEntryPointHandler;
import com.greatchn.authorization_server.handler.MetadataSourceHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import javax.annotation.Resource;
/**
* @AuthorizationServerConfig: 授权服务 config
* @author: ZBoHang
* @time: 2023/2/27 13:16
*/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private AuthEntryPointHandler authEntryPointHandler;
@Resource
private AccDeniedHandler accDeniedHandler;
@Resource
private UserDetailsService userDetailsHandler;
@Resource
private MetadataSourceHandler metadataSourceHandler;
@Resource
private AccDecisionHandler accDecisionHandler;
@Resource
private SecurityFilterConfig securityFilterConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 允许postman等测试
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler(this.accDeniedHandler)
.authenticationEntryPoint(this.authEntryPointHandler)
.and()
.authorizeRequests()
// .antMatchers("/login/**").permitAll()
// .antMatchers("/admin/**").hasRole("ADMIN")
// .antMatchers("/**")
.anyRequest()
.authenticated()
// 自定义角色权限
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
// 设置角色权限
object.setSecurityMetadataSource(metadataSourceHandler);
// 判定角色权限
object.setAccessDecisionManager(accDecisionHandler);
return object;
}
})
.and()
// 跨域
.cors().disable()
.apply(this.securityFilterConfig)
;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 设置自定义的userDetailsService
auth.userDetailsService(this.userDetailsHandler)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
// TODO: 2023/2/27 不加密
return NoOpPasswordEncoder.getInstance();
}
}
package com.greatchn.authorization_server.constant;
import org.springframework.util.AntPathMatcher;
/**
* @Constant: constant
* @author: ZBoHang
* @time: 2023/2/20 16:08
*/
public class Constant {
private Constant() {}
/**
* JWT 加密 密钥
*/
public static final String JWT_SECRET_KEY = "uiop";
/**
* 路径匹配对象
*/
public static final AntPathMatcher ANTPATHMATCHER = new AntPathMatcher();
/**
* 不需要登录角色
*/
public static final String DEFAULT_ROLE = "ROLE_NOT_NEED_LOGIN";
/**
* token 到期时间
*/
public static final Long TOKEN_EXPIRES = Long.valueOf("3600");
}
package com.greatchn.authorization_server.constant;
/**
* 结果集枚举
* @author: ZBoHang
* @time: 2023/2/8 10:54
*/
public enum ResultEnum {
SUCCESS(200, "请求成功"),
PARAMS_NONE_PASS(400, "参数校验未通过"),
NONE_AUTH(401, "本次访问没有权限"),
FAILURE(500, "服务器内部异常"),;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return this.code;
}
public String getMsg() {
return this.msg;
}
}
package com.greatchn.authorization_server.exception;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @ApiException: 自定义api异常
* @author: ZBoHang
* @time: 2021/12/9 13:40
*/
@Data
@Accessors(chain = true)
public class ApiException extends RuntimeException {
/**
* 错误码
*/
private Integer code;
/**
* 错误消息
*/
private String msg;
public ApiException(Integer code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
}
package com.greatchn.authorization_server.exception;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @ServiceException: 自定义srv异常
* @author: ZBoHang
* @time: 2021/12/9 13:41
*/
@Data
@Accessors(chain = true)
public class ServiceException extends RuntimeException {
/**
* 错误码
*/
private Integer code;
/**
* 错误消息
*/
private String msg;
public ServiceException(Integer code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
}
package com.greatchn.authorization_server.filter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.greatchn.authorization_server.exception.ApiException;
import com.greatchn.authorization_server.util.Result;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.stereotype.Component;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* @ExceptionFilter: 异常过滤
* @author: ZBoHang
* @time: 2023/2/9 11:44
*/
@Component
public class ExceptionFilter extends ExceptionTranslationFilter {
public ExceptionFilter(AuthenticationEntryPoint authenticationEntryPoint) {
super(authenticationEntryPoint);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
super.doFilter(request, response, chain);
} catch (Exception e) {
if (e instanceof ApiException) {
response.setContentType(ContentType.JSON.getValue());
response.setCharacterEncoding(CharsetUtil.UTF_8);
ApiException apiException = (ApiException) e;
response.getWriter().write(JSONUtil.toJsonPrettyStr(Result.failure(apiException.getCode(), apiException.getMsg())));
return;
}
e.printStackTrace();
}
}
}
package com.greatchn.authorization_server.filter;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.greatchn.authorization_server.handler.UserDetailsHandler;
import com.greatchn.authorization_server.util.ApiAssert;
import com.greatchn.authorization_server.util.RedisClient;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @TokenFilter: token filter
* @author: ZBoHang
* @time: 2023/2/8 13:25
*/
@Component
public class TokenFilter extends GenericFilterBean {
@Resource
private UserDetailsHandler userDetailsHandler;
@Resource
private RedisClient redisClient;
@Resource
private JdbcClientDetailsService jdbcClientDetailsService;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
// TODO: 2023/2/8
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String authToken = httpServletRequest.getHeader("token");
Authentication authentication;
if (StrUtil.isNotBlank(authToken)) {
// 解析用户
String oauthUserInfoJsonStr = this.redisClient.get(authToken);
ApiAssert.noneBlank(oauthUserInfoJsonStr, "token过期!");
String userName = JSONUtil.parseObj(oauthUserInfoJsonStr).getStr("userName");
// 查询用户信息
UserDetails details = this.userDetailsHandler.loadUserByUsername(userName);
// 查询指向系统
String directedSystem = httpServletRequest.getParameter("directed_system");
// 申请访问资源相关路径
if (StrUtil.isNotBlank(directedSystem)) {
ClientDetails clientDetails = jdbcClientDetailsService.loadClientByClientId(directedSystem);
ApiAssert.notNull(clientDetails, "指向系统不存在!");
authentication = new OAuth2Authentication(
new OAuth2Request(
MapUtil.of(Pair.of("userName", userName)),
clientDetails.getClientId(),
clientDetails.getAuthorities(),
clientDetails.isAutoApprove(String.join(StrUtil.EMPTY, clientDetails.getScope())),
clientDetails.getScope(),
clientDetails.getResourceIds(),
null, null, MapUtil.of(Pair.of("userName", userName))
),
new UsernamePasswordAuthenticationToken(details, details.getPassword(), details.getAuthorities()));
} else {
// 普通路径认证
authentication = new UsernamePasswordAuthenticationToken(details, details.getPassword(), details.getAuthorities());
}
// 存放认证信息 恢复session - 若没有则会提示登录
SecurityContextHolder.getContext().setAuthentication(authentication);
}
// 调用后续的Filter,未能复原“session”,SecurityContext中没有想过信息,后面的流程会检测出"需要登录"
filterChain.doFilter(servletRequest, servletResponse);
}
}
package com.greatchn.authorization_server.handler;
import cn.hutool.core.util.StrUtil;
import com.greatchn.authorization_server.constant.Constant;
import com.greatchn.authorization_server.constant.ResultEnum;
import com.greatchn.authorization_server.exception.ApiException;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* @AccDecisionManager: 判断角色属性
* @author: ZBoHang
* @time: 2023/2/9 17:02
*/
@Component("accDecisionHandler")
public class AccDecisionHandler implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
for(ConfigAttribute configAttribute : configAttributes){
//当前url所需要的角色
String needRole = configAttribute.getAttribute();
// 访问url的角色和不需要登录角色一致 跳过
if (StrUtil.equals(Constant.DEFAULT_ROLE, needRole)) {
return;
}
//判断用户角色是否为url所需角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for(GrantedAuthority grantedAuthority : authorities){
if(grantedAuthority.getAuthority().equals(needRole)){
return;
}
}
}
throw new ApiException(ResultEnum.NONE_AUTH.getCode(), ResultEnum.NONE_AUTH.getMsg());
}
@Override
public boolean supports(ConfigAttribute attribute) {
return false;
}
@Override
public boolean supports(Class<?> clazz) {
return false;
}
}
package com.greatchn.authorization_server.handler;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @AccDeniedHandler: 访问权限异常处理
* @author: ZBoHang
* @time: 2023/2/9 11:17
*/
@Component
public class AccDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType(ContentType.JSON.getValue());
response.setCharacterEncoding(CharsetUtil.UTF_8);
response.getWriter().write("服务器拒绝访问!");
}
}
package com.greatchn.authorization_server.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @AccessTokenConverter: jwt 拓展
* @author: ZBoHang
* @time: 2023/3/2 15:15
*/
@Component
public class AccessTokenConverter extends DefaultAccessTokenConverter {
@Override
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
User principal = (User) currentAuthentication.getPrincipal();
String username = principal.getUsername();
Collection<GrantedAuthority> authorities = principal.getAuthorities();
Map<String, String> payLoadMap = (Map<String, String>) super.convertAccessToken(token, authentication);
payLoadMap.put("userName", username);
payLoadMap.put("customerAuthorities", authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining("|")));
return payLoadMap;
}
}
package com.greatchn.authorization_server.handler;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @SecurityExceptionFilter: 认证异常处理
* @author: ZBoHang
* @time: 2023/2/9 9:06
*/
@Component
public class AuthEntryPointHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType(ContentType.JSON.getValue());
response.setCharacterEncoding(CharsetUtil.UTF_8);
response.getWriter().write("身份认证时出现异常!");
}
}
package com.greatchn.authorization_server.handler;
import com.greatchn.authorization_server.exception.ApiException;
import com.greatchn.authorization_server.exception.ServiceException;
import com.greatchn.authorization_server.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @Description: 异常处理器
* @Author: zhengbohang
* @Date: 2021/10/3 10:32
*/
@Slf4j
@RestControllerAdvice
public class ExceptionsHandler {
@ExceptionHandler(ApiException.class)
public Result apiExceptionHandler(ApiException ex) {
return Result.failure(ex.getCode(), ex.getMsg());
}
@ExceptionHandler(ServiceException.class)
public Result srvExceptionHandler(ServiceException ex) {
return Result.failure(ex.getCode(), ex.getMsg());
}
@ExceptionHandler(Exception.class)
public Result commonExceptionHandler(Exception ex) {
// TODO: 2023/2/8
return Result.failure("fail!");
}
}
package com.greatchn.authorization_server.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.greatchn.authorization_server.constant.Constant;
import com.greatchn.authorization_server.util.ServiceAssert;
import com.greatchn.authorization_server.web.po.OauthFunctionInfo;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfo;
import com.greatchn.authorization_server.web.srv.OauthConfigSrv;
import com.greatchn.authorization_server.web.srv.OauthFunctionInfoSrv;
import com.greatchn.authorization_server.web.srv.OauthRoleFunctionConnectionSrv;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* @FilterMetadataSource: 设置角色权限
* @author: ZBoHang
* @time: 2023/2/9 16:50
*/
@Order
@Component("metadataSourceHandler")
public class MetadataSourceHandler implements FilterInvocationSecurityMetadataSource {
@Resource
private OauthConfigSrv oauthConfigSrv;
@Resource
private OauthRoleFunctionConnectionSrv oauthRoleFunctionConnectionSrv;
@Resource
private OauthFunctionInfoSrv oauthFunctionInfoSrv;
@Override
public Collection<ConfigAttribute> getAttributes(Object object) {
//获取请求的url
String requestUrl = ((FilterInvocation) object).getRequestUrl();
String noAuthenticationPathStr = this.oauthConfigSrv.getValidConfigByKey("no_authentication_path_str").getValue();
// 首先匹配 不需要认证的url
List<String> noAuthenticationPathList = StrUtil.split(noAuthenticationPathStr, StrUtil.COMMA);
boolean matchResult = noAuthenticationPathList.stream().anyMatch(url -> Constant.ANTPATHMATCHER.match(url, requestUrl));
// 不需要认证的url 返回默认角色
if (matchResult) {
return SecurityConfig.createList(Constant.DEFAULT_ROLE);
}
// 匹配url的所有功能
List<OauthFunctionInfo> oauthFunctionInfoList = this.oauthFunctionInfoSrv.getAll()
.stream()
.filter(vo -> Constant.ANTPATHMATCHER.match(vo.getFunctionName(), requestUrl))
.collect(Collectors.toList());
// 查询功能对应的角色
List<String> conformingRoleList =
this.oauthRoleFunctionConnectionSrv.getAllRoleIdByFunctionIds(
oauthFunctionInfoList.stream().map(OauthFunctionInfo::getFunctionId).collect(Collectors.toList())
).stream().map(OauthRoleGroupInfo::getRoleGroupName).collect(Collectors.toList());
//没匹配的url 路径异常
ServiceAssert.isFalse(CollUtil.isEmpty(conformingRoleList), "路径异常!");
return SecurityConfig.createList(conformingRoleList.toArray(new String[0]));
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return false;
}
}
package com.greatchn.authorization_server.handler;
import com.greatchn.authorization_server.util.ServiceAssert;
import com.greatchn.authorization_server.web.po.OauthUserInfo;
import com.greatchn.authorization_server.web.srv.OauthUserInfoSrv;
import org.springframework.security.core.GrantedAuthority;
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.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @UserDetailsHandler: 用户详情处理
* @author: ZBoHang
* @time: 2023/2/28 10:34
*/
@Component("userDetailsHandler")
public class UserDetailsHandler implements UserDetailsService {
@Resource
private OauthUserInfoSrv oauthUserInfoSrv;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
OauthUserInfo userInfo = this.oauthUserInfoSrv.getByUserName(username);
ServiceAssert.notNull(userInfo, "用户不存在!");
Set<String> roleNameSet = this.oauthUserInfoSrv.getRoleNameByUserName(username);
// 包装用户
List<GrantedAuthority> grantedAuthorities = new ArrayList<>(12);
for (String role : roleNameSet) {
grantedAuthorities.add(new SimpleGrantedAuthority(role));
}
return new User(username, userInfo.getPassword(), grantedAuthorities);
}
}
package com.greatchn.authorization_server.util;
import cn.hutool.core.util.StrUtil;
import com.greatchn.authorization_server.constant.ResultEnum;
import com.greatchn.authorization_server.exception.ApiException;
import org.springframework.lang.Nullable;
/**
* @ApiAssert: api 断言
* @author: ZBoHang
* @time: 2021/12/9 17:07
*/
public class ApiAssert {
private ApiAssert() {}
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void isFalse(boolean expression, String message) {
if (expression) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void isNull(@Nullable Object object, String message) {
if (object != null) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void notNull(@Nullable Object object, String message) {
if (object == null) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void hasBlank(@Nullable String text, String message) {
if (!StrUtil.hasBlank(text)) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void noneBlank(@Nullable String text, String message) {
if (StrUtil.hasBlank(text)) {
throw new ApiException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
}
package com.greatchn.authorization_server.util;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @Description: 操作redis的工具类
* @Author: zhengbohang
* @Date: 2021/10/3 19:29
*/
@Component
public class RedisClient {
@Autowired
private RedisTemplate redisTemplate;
/**
* @description: 检查键是否存在
* @author: zhengbohang
* @date: 2021/10/3 19:38
*/
public Boolean hasKey(String key) {
return Boolean.TRUE.equals(this.redisTemplate.hasKey(key));
}
/**
* 获取指定key的生存时间
* @author: ZBoHang
* @time: 2022/1/17 16:10
*/
public Long ttl(String key) {
return this.redisTemplate.opsForValue().getOperations().getExpire(key);
}
/**
* @description: 设置带有生存时间的 单位: 秒
* @author: zhengbohang
* @date: 2021/10/3 19:42
*/
public void set(String key, String value, Long seconds) {
this.redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
}
/**
* @description: 拿到key 对应的值
* @author: zhengbohang
* @date: 2021/10/3 19:44
*/
public String get(String key) {
Object o = this.redisTemplate.opsForValue().get(key);
return null == o ? StrUtil.EMPTY : o.toString();
}
/**
* 删除匹配key 的键值对
* @author: ZBoHang
* @time: 2021/10/11 17:12
*/
public void del(String key) {
this.redisTemplate.delete(key);
}
/**
* 添加值 到指定集合set
* @author: ZBoHang
* @time: 2022/1/6 10:22
*/
public void sadd(String key, String value) {
this.redisTemplate.opsForSet().add(key, value);
}
/**
* 删除值 从指定集合set
* @author: ZBoHang
* @time: 2022/1/6 11:01
*/
public void sremove(String key, String value) {
this.redisTemplate.opsForSet().remove(key, value);
}
/**
* 查找指定 键值 是否存在
* @author: ZBoHang
* @time: 2022/1/6 11:22
*/
public boolean isMember(String key, String value) {
return this.redisTemplate.opsForSet().isMember(key, value);
}
/**
* 获取指定set的size
* @author: ZBoHang
* @time: 2022/1/6 11:56
*/
public Long ssize(String key) {
return this.redisTemplate.opsForSet().size(key);
}
/**
* 新增 统计(类型)
* @param key 键
* @param value 值
* @return: void
* @author: ZBoHang
* @time: 2022/1/17 13:10
*/
public void addHyperLog(String key, String value) {
this.redisTemplate.opsForHyperLogLog().add(key, value);
}
/**
* 计数
* @param key 键
* @return: java.lang.Long
* @author: ZBoHang
* @time: 2022/1/17 13:25
*/
public Long sizeHyperLog(String key) {
return this.redisTemplate.opsForHyperLogLog().size(key);
}
/**
* 合并所有旧键结果至新键
* @param newKey 新键
* @param oldKeyList 旧键集合
* @return: java.lang.Long
* @author: ZBoHang
* @time: 2022/1/17 13:25
*/
public Long unionHyperLog(String newKey, List<String> oldKeyList) {
return this.redisTemplate.opsForHyperLogLog().union(newKey, oldKeyList.toArray());
}
/**
* 移除指定键
* @param key 键
* @return: void
* @author: ZBoHang
* @time: 2022/1/17 13:27
*/
public void deleteHyperLog(String key) {
this.redisTemplate.opsForHyperLogLog().delete(key);
}
}
package com.greatchn.authorization_server.util;
import com.greatchn.authorization_server.constant.ResultEnum;
import lombok.Getter;
import java.io.Serializable;
/**
* @Description: ctrl统一返回
* @Author: zhengbohang
* @Date: 2021/10/3 10:43
*/
@Getter
public class Result implements Serializable {
private static final long serialVersionUID = -6166789405232241629L;
private Integer code;
private String msg;
private Object bean;
private Result() {
}
public static Result success() {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = ResultEnum.SUCCESS.getMsg();
return result;
}
public static Result success(String message) {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = message;
return result;
}
public static Result success(Object obj) {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = ResultEnum.SUCCESS.getMsg();
result.bean = obj;
return result;
}
public static Result failure() {
Result result = new Result();
result.code = ResultEnum.FAILURE.getCode();
result.msg = ResultEnum.FAILURE.getMsg();
return result;
}
public static Result failure(String message) {
Result result = new Result();
result.code = ResultEnum.FAILURE.getCode();
result.msg = message;
return result;
}
public static Result failure(Integer code, String msg) {
Result result = new Result();
result.code = code;
result.msg = msg;
return result;
}
public static Result noneAuth() {
Result result = new Result();
result.code = ResultEnum.NONE_AUTH.getCode();
result.msg = ResultEnum.NONE_AUTH.getMsg();
return result;
}
}
package com.greatchn.authorization_server.util;
import cn.hutool.core.util.StrUtil;
import com.greatchn.authorization_server.constant.ResultEnum;
import com.greatchn.authorization_server.exception.ServiceException;
import org.springframework.lang.Nullable;
/**
* @ServiceAssert: srv 断言
* @author: ZBoHang
* @time: 2021/12/9 17:08
*/
public class ServiceAssert {
private ServiceAssert() {}
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void isFalse(boolean expression, String message) {
if (expression) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void isNull(@Nullable Object object, String message) {
if (object != null) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void notNull(@Nullable Object object, String message) {
if (object == null) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void hasBlank(@Nullable String text, String message) {
if (!StrUtil.hasBlank(text)) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
public static void noneBlank(@Nullable String text, String message) {
if (StrUtil.hasBlank(text)) {
throw new ServiceException(ResultEnum.PARAMS_NONE_PASS.getCode(), message);
}
}
}
package com.greatchn.authorization_server.web.controller;
import com.greatchn.authorization_server.util.ApiAssert;
import com.greatchn.authorization_server.util.Result;
import com.greatchn.authorization_server.web.srv.LoginSrv;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @LoginController: login
* @author: ZBoHang
* @time: 2023/2/28 16:08
*/
@RestController
@RequestMapping("/login")
public class LoginController {
@Resource
private LoginSrv loginSrv;
/**
* login
*/
@PostMapping("/login")
public Result login(String userName, String password) {
ApiAssert.noneBlank(userName, "用户名不能为空!");
ApiAssert.noneBlank(password, "密码不能为空!");
String token = this.loginSrv.login(userName, password);
return Result.success(token);
}
/**
* check
*/
@PostMapping("/check")
public Result check(String userName) {
return Result.success(userName);
}
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @IOauthConfigDao: OauthConfig dao
* @author: ZBoHang
* @time: 2023/2/28 13:55
*/
@Repository
public interface IOauthConfigDao extends JpaRepository<OauthConfig, String>, JpaSpecificationExecutor<OauthConfig> {
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthFunctionInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @IOauthFunctionInfoDao: OauthFunctionInfo dao
* @author: ZBoHang
* @time: 2023/2/27 17:35
*/
@Repository
public interface IOauthFunctionInfoDao extends JpaRepository<OauthFunctionInfo, Integer>, JpaSpecificationExecutor<OauthFunctionInfo> {
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthRoleFunctionConnection;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @IOauthRoleFunctionConnectionDao: OauthRoleFunctionConnection dao
* @author: ZBoHang
* @time: 2023/2/28 9:15
*/
@Repository
public interface IOauthRoleFunctionConnectionDao extends JpaRepository<OauthRoleFunctionConnection, Integer>,
JpaSpecificationExecutor<OauthRoleFunctionConnection> {
/**
* find by functionId
*/
public List<OauthRoleFunctionConnection> findByFunctionIdIn(List<Integer> functionIdList);
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfo;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfoPK;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @IOauthRoleGroupInfoDao: OauthRoleGroupInfo dao
* @author: ZBoHang
* @time: 2023/2/28 9:17
*/
@Repository
public interface IOauthRoleGroupInfoDao extends JpaRepository<OauthRoleGroupInfo, OauthRoleGroupInfoPK>, JpaSpecificationExecutor<OauthRoleGroupInfo> {
/**
* find by role group id in
*/
public List<OauthRoleGroupInfo> findByRoleGroupIdIn(List<Integer> list);
/**
* find by user group id in
*/
public List<OauthRoleGroupInfo> findByBelongToUserGroupIdIn(List<Integer> list);
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthUserGroupInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @IOauthUserGroupInfoDao: OauthUserGroupInfo dao
* @author: ZBoHang
* @time: 2023/2/28 9:18
*/
@Repository
public interface IOauthUserGroupInfoDao extends JpaRepository<OauthUserGroupInfo, Integer>, JpaSpecificationExecutor<OauthUserGroupInfo> {
/**
* find by id in
*/
public List<OauthUserGroupInfo> findByUserGroupIdIn(List<Integer> list);
}
package com.greatchn.authorization_server.web.dao;
import com.greatchn.authorization_server.web.po.OauthUserInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @IOauthUserInfoDao: OauthUserInfo dao
* @author: ZBoHang
* @time: 2023/2/28 9:20
*/
@Repository
public interface IOauthUserInfoDao extends JpaRepository<OauthUserInfo, String>, JpaSpecificationExecutor<OauthUserInfo> {
}
package com.greatchn.authorization_server.web.po;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
/**
* @OauthConfig:
* @author: ZBoHang
* @time: 2023/2/28 13:54
*/
@Entity
@Table(name = "oauth_config", schema = "sso", catalog = "")
@Proxy(lazy = false)
public class OauthConfig implements Serializable {
private static final long serialVersionUID = -2158423855887215070L;
private String key;
private String value;
private String desc;
private String state;
@Id
@Column(name = "key", nullable = false, length = 255)
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Basic
@Column(name = "value", nullable = true, length = 255)
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Basic
@Column(name = "desc", nullable = true, length = 255)
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Basic
@Column(name = "state", nullable = true, length = 1)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthConfig that = (OauthConfig) o;
return Objects.equals(key, that.key) && Objects.equals(value, that.value) && Objects.equals(desc, that.desc) && Objects.equals(state, that.state);
}
@Override
public int hashCode() {
return Objects.hash(key, value, desc, state);
}
}
package com.greatchn.authorization_server.web.po;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* @OauthFunctionInfo:
* @author: ZBoHang
* @time: 2023/2/28 9:07
*/
@Entity
@Table(name = "oauth_function_info", schema = "sso", catalog = "")
public class OauthFunctionInfo implements Serializable {
private static final long serialVersionUID = 6981162969486304865L;
private Integer functionId;
private String functionName;
private String desc;
private String state;
private Timestamp createTime;
@Id
@Column(name = "function_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getFunctionId() {
return functionId;
}
public void setFunctionId(Integer functionId) {
this.functionId = functionId;
}
@Basic
@Column(name = "function_name", nullable = true, length = 255)
public String getFunctionName() {
return functionName;
}
public void setFunctionName(String functionName) {
this.functionName = functionName;
}
@Basic
@Column(name = "desc", nullable = true, length = 255)
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Basic
@Column(name = "state", nullable = true, length = 1)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Basic
@Column(name = "create_time", nullable = true)
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthFunctionInfo that = (OauthFunctionInfo) o;
return Objects.equals(functionId, that.functionId) && Objects.equals(functionName, that.functionName) && Objects.equals(desc, that.desc) && Objects.equals(state, that.state) && Objects.equals(createTime, that.createTime);
}
@Override
public int hashCode() {
return Objects.hash(functionId, functionName, desc, state, createTime);
}
}
package com.greatchn.authorization_server.web.po;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* @OauthRoleFunctionConnection:
* @author: ZBoHang
* @time: 2023/2/28 10:23
*/
@Entity
@Table(name = "oauth_role_function_connection", schema = "sso", catalog = "")
public class OauthRoleFunctionConnection implements Serializable {
private Integer id;
private Integer roleGroupId;
private Integer belongToUserGroupId;
private Integer functionId;
private Timestamp createTime;
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Basic
@Column(name = "role_group_id", nullable = true)
public Integer getRoleGroupId() {
return roleGroupId;
}
public void setRoleGroupId(Integer roleGroupId) {
this.roleGroupId = roleGroupId;
}
@Basic
@Column(name = "belong_to_user_group_id", nullable = true)
public Integer getBelongToUserGroupId() {
return belongToUserGroupId;
}
public void setBelongToUserGroupId(Integer belongToUserGroupId) {
this.belongToUserGroupId = belongToUserGroupId;
}
@Basic
@Column(name = "function_id", nullable = true)
public Integer getFunctionId() {
return functionId;
}
public void setFunctionId(Integer functionId) {
this.functionId = functionId;
}
@Basic
@Column(name = "create_time", nullable = true)
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthRoleFunctionConnection that = (OauthRoleFunctionConnection) o;
return Objects.equals(id, that.id) && Objects.equals(roleGroupId, that.roleGroupId) && Objects.equals(belongToUserGroupId, that.belongToUserGroupId) && Objects.equals(functionId, that.functionId) && Objects.equals(createTime, that.createTime);
}
@Override
public int hashCode() {
return Objects.hash(id, roleGroupId, belongToUserGroupId, functionId, createTime);
}
}
package com.greatchn.authorization_server.web.po;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* @OauthRoleGroupInfo:
* @author: ZBoHang
* @time: 2023/2/28 9:07
*/
@Entity
@Table(name = "oauth_role_group_info", schema = "sso", catalog = "")
@IdClass(OauthRoleGroupInfoPK.class)
public class OauthRoleGroupInfo implements Serializable {
private static final long serialVersionUID = -2214980254532790039L;
private Integer roleGroupId;
private String roleGroupName;
private Integer belongToUserGroupId;
private Integer perentId;
private String desc;
private String state;
private Timestamp createTime;
@Id
@Column(name = "role_group_id", nullable = false)
public Integer getRoleGroupId() {
return roleGroupId;
}
public void setRoleGroupId(Integer roleGroupId) {
this.roleGroupId = roleGroupId;
}
@Basic
@Column(name = "role_group_name", nullable = true, length = 255)
public String getRoleGroupName() {
return roleGroupName;
}
public void setRoleGroupName(String roleGroupName) {
this.roleGroupName = roleGroupName;
}
@Id
@Column(name = "belong_to_user_group_id", nullable = false)
public Integer getBelongToUserGroupId() {
return belongToUserGroupId;
}
public void setBelongToUserGroupId(Integer belongToUserGroupId) {
this.belongToUserGroupId = belongToUserGroupId;
}
@Basic
@Column(name = "perent_id", nullable = true)
public Integer getPerentId() {
return perentId;
}
public void setPerentId(Integer perentId) {
this.perentId = perentId;
}
@Basic
@Column(name = "desc", nullable = true, length = 255)
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Basic
@Column(name = "state", nullable = true, length = 1)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Basic
@Column(name = "create_time", nullable = true)
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthRoleGroupInfo that = (OauthRoleGroupInfo) o;
return Objects.equals(roleGroupId, that.roleGroupId) && Objects.equals(roleGroupName, that.roleGroupName) && Objects.equals(belongToUserGroupId, that.belongToUserGroupId) && Objects.equals(perentId, that.perentId) && Objects.equals(desc, that.desc) && Objects.equals(state, that.state) && Objects.equals(createTime, that.createTime);
}
@Override
public int hashCode() {
return Objects.hash(roleGroupId, roleGroupName, belongToUserGroupId, perentId, desc, state, createTime);
}
}
package com.greatchn.authorization_server.web.po;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Objects;
/**
* @OauthRoleGroupInfoPK:
* @author: ZBoHang
* @time: 2023/2/28 9:07
*/
public class OauthRoleGroupInfoPK implements Serializable {
private Integer roleGroupId;
private Integer belongToUserGroupId;
@Column(name = "role_group_id", nullable = false)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getRoleGroupId() {
return roleGroupId;
}
public void setRoleGroupId(Integer roleGroupId) {
this.roleGroupId = roleGroupId;
}
@Column(name = "belong_to_user_group_id", nullable = false)
@Id
public Integer getBelongToUserGroupId() {
return belongToUserGroupId;
}
public void setBelongToUserGroupId(Integer belongToUserGroupId) {
this.belongToUserGroupId = belongToUserGroupId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthRoleGroupInfoPK that = (OauthRoleGroupInfoPK) o;
return Objects.equals(roleGroupId, that.roleGroupId) && Objects.equals(belongToUserGroupId, that.belongToUserGroupId);
}
@Override
public int hashCode() {
return Objects.hash(roleGroupId, belongToUserGroupId);
}
}
package com.greatchn.authorization_server.web.po;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* @OauthUserGroupInfo:
* @author: ZBoHang
* @time: 2023/2/28 9:07
*/
@Entity
@Table(name = "oauth_user_group_info", schema = "sso", catalog = "")
public class OauthUserGroupInfo implements Serializable {
private static final long serialVersionUID = 5069742015346758571L;
private Integer userGroupId;
private String userGroupName;
private Integer parentId;
private String desc;
private String state;
private Timestamp createTime;
@Id
@Column(name = "user_group_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getUserGroupId() {
return userGroupId;
}
public void setUserGroupId(Integer userGroupId) {
this.userGroupId = userGroupId;
}
@Basic
@Column(name = "user_group_name", nullable = true, length = 255)
public String getUserGroupName() {
return userGroupName;
}
public void setUserGroupName(String userGroupName) {
this.userGroupName = userGroupName;
}
@Basic
@Column(name = "parent_id", nullable = true)
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
@Basic
@Column(name = "desc", nullable = true, length = 255)
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Basic
@Column(name = "state", nullable = true, length = 1)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Basic
@Column(name = "create_time", nullable = true)
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthUserGroupInfo that = (OauthUserGroupInfo) o;
return Objects.equals(userGroupId, that.userGroupId) && Objects.equals(userGroupName, that.userGroupName) && Objects.equals(parentId, that.parentId) && Objects.equals(desc, that.desc) && Objects.equals(state, that.state) && Objects.equals(createTime, that.createTime);
}
@Override
public int hashCode() {
return Objects.hash(userGroupId, userGroupName, parentId, desc, state, createTime);
}
}
package com.greatchn.authorization_server.web.po;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* @OauthUserInfo:
* @author: ZBoHang
* @time: 2023/2/28 9:07
*/
@Entity
@Proxy(lazy = false)
@Table(name = "oauth_user_info", schema = "sso", catalog = "")
public class OauthUserInfo implements Serializable {
private static final long serialVersionUID = -7416046370991464027L;
private String userName;
private String password;
private String belongToUserGroup;
private String belongToRoleGroup;
private String state;
private Timestamp createTime;
@Id
@Column(name = "user_name", nullable = false, length = 255)
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Basic
@Column(name = "password", nullable = true, length = 255)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Basic
@Column(name = "belong_to_user_group", nullable = true, length = 255)
public String getBelongToUserGroup() {
return belongToUserGroup;
}
public void setBelongToUserGroup(String belongToUserGroup) {
this.belongToUserGroup = belongToUserGroup;
}
@Basic
@Column(name = "belong_to_role_group", nullable = true, length = 255)
public String getBelongToRoleGroup() {
return belongToRoleGroup;
}
public void setBelongToRoleGroup(String belongToRoleGroup) {
this.belongToRoleGroup = belongToRoleGroup;
}
@Basic
@Column(name = "state", nullable = true, length = 1)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Basic
@Column(name = "create_time", nullable = true)
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OauthUserInfo that = (OauthUserInfo) o;
return Objects.equals(userName, that.userName) && Objects.equals(password, that.password) && Objects.equals(belongToUserGroup, that.belongToUserGroup) && Objects.equals(belongToRoleGroup, that.belongToRoleGroup) && Objects.equals(state, that.state) && Objects.equals(createTime, that.createTime);
}
@Override
public int hashCode() {
return Objects.hash(userName, password, belongToUserGroup, belongToRoleGroup, state, createTime);
}
}
package com.greatchn.authorization_server.web.srv;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.greatchn.authorization_server.constant.Constant;
import com.greatchn.authorization_server.util.RedisClient;
import com.greatchn.authorization_server.util.ServiceAssert;
import com.greatchn.authorization_server.web.po.OauthUserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @LoginSrv: login srv
* @author: ZBoHang
* @time: 2023/3/1 13:20
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class LoginSrv {
@Resource
private OauthUserInfoSrv oauthUserInfoSrv;
@Autowired
private RedisClient redisClient;
/**
* login
*/
public String login(String userName, String password) {
OauthUserInfo oauthUserInfo = this.oauthUserInfoSrv.getByUserName(userName);
ServiceAssert.notNull(oauthUserInfo, "用户不存在!");
ServiceAssert.isTrue(StrUtil.equals(password, oauthUserInfo.getPassword()), "密码错误!");
String token = IdUtil.fastSimpleUUID();
this.redisClient.set(token, JSONUtil.toJsonStr(oauthUserInfo), Constant.TOKEN_EXPIRES);
return token;
}
}
package com.greatchn.authorization_server.web.srv;
import com.greatchn.authorization_server.web.dao.IOauthConfigDao;
import com.greatchn.authorization_server.web.po.OauthConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @OauthConfigSrv: OauthConfig srv
* @author: ZBoHang
* @time: 2023/2/28 13:56
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthConfigSrv {
@Autowired
private IOauthConfigDao iOauthConfigDao;
/**
* get by key
*/
public OauthConfig getValidConfigByKey(String key) {
return this.iOauthConfigDao.getOne(key);
}
}
package com.greatchn.authorization_server.web.srv;
import com.greatchn.authorization_server.web.dao.IOauthFunctionInfoDao;
import com.greatchn.authorization_server.web.po.OauthFunctionInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
/**
* @OauthFunctionInfoSrv: OauthFunctionInfo srv
* @author: ZBoHang
* @time: 2023/2/28 9:24
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthFunctionInfoSrv {
@Resource
private IOauthFunctionInfoDao iOauthFunctionInfoDao;
/**
* getAll
*/
public List<OauthFunctionInfo> getAll() {
return this.iOauthFunctionInfoDao.findAll();
}
}
package com.greatchn.authorization_server.web.srv;
import com.greatchn.authorization_server.web.dao.IOauthRoleFunctionConnectionDao;
import com.greatchn.authorization_server.web.dao.IOauthRoleGroupInfoDao;
import com.greatchn.authorization_server.web.po.OauthRoleFunctionConnection;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @OauthRoleFunctionConnectionSrv: OauthRoleFunctionConnection srv
* @author: ZBoHang
* @time: 2023/2/28 9:24
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthRoleFunctionConnectionSrv {
@Resource
private IOauthRoleFunctionConnectionDao iOauthRoleFunctionConnectionDao;
@Resource
private IOauthRoleGroupInfoDao iOauthRoleGroupInfoDao;
/**
* 通过功能id 获取可用角色
*/
public List<OauthRoleGroupInfo> getAllRoleIdByFunctionIds(List<Integer> functionIdList) {
List<OauthRoleFunctionConnection> roleFunctionConnList = this.iOauthRoleFunctionConnectionDao.findByFunctionIdIn(functionIdList);
List<Integer> roleGroupIdList =
roleFunctionConnList.stream().map(OauthRoleFunctionConnection::getRoleGroupId).collect(Collectors.toList());
return this.iOauthRoleGroupInfoDao.findByRoleGroupIdIn(roleGroupIdList);
}
}
package com.greatchn.authorization_server.web.srv;
import com.greatchn.authorization_server.web.dao.IOauthRoleGroupInfoDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @OauthRoleGroupInfoSrv: OauthRoleGroupInfo srv
* @author: ZBoHang
* @time: 2023/2/28 9:25
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthRoleGroupInfoSrv {
@Resource
private IOauthRoleGroupInfoDao iOauthRoleGroupInfoDao;
}
package com.greatchn.authorization_server.web.srv;
import com.greatchn.authorization_server.web.dao.IOauthUserGroupInfoDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @OauthUserGroupInfoSrv: OauthUserGroupInfo srv
* @author: ZBoHang
* @time: 2023/2/28 9:26
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthUserGroupInfoSrv {
@Resource
private IOauthUserGroupInfoDao iOauthUserGroupInfoDao;
}
package com.greatchn.authorization_server.web.srv;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.greatchn.authorization_server.util.ServiceAssert;
import com.greatchn.authorization_server.web.dao.IOauthRoleGroupInfoDao;
import com.greatchn.authorization_server.web.dao.IOauthUserInfoDao;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfo;
import com.greatchn.authorization_server.web.po.OauthUserInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @OauthUserInfoSrv: OauthUserInfo srv
* @author: ZBoHang
* @time: 2023/2/28 9:27
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OauthUserInfoSrv {
@Resource
private IOauthUserInfoDao iOauthUserInfoDao;
@Resource
private IOauthRoleGroupInfoDao iOauthRoleGroupInfoDao;
/**
* get function by username
*/
public Set<String> getRoleNameByUserName(String userName) {
OauthUserInfo oauthUserInfo = this.getByUserName(userName);
ServiceAssert.notNull(oauthUserInfo, "用户不存在!");
Set<String> roleStrSet = new HashSet<>(12);
// 所属用户组
List<Integer> userGroupIdList =
StrUtil.split(oauthUserInfo.getBelongToUserGroup(), StrUtil.COMMA).stream()
.map(Integer::valueOf).collect(Collectors.toList());
if (CollUtil.isNotEmpty(userGroupIdList)) {
// 用户组对应的所有角色
List<OauthRoleGroupInfo> roleGroupInfo = this.iOauthRoleGroupInfoDao.findByBelongToUserGroupIdIn(userGroupIdList);
roleGroupInfo.stream().map(OauthRoleGroupInfo::getRoleGroupName).forEach(roleStrSet::add);
}
// 所属角色组
List<Integer> roleGroupIdList =
StrUtil.split(oauthUserInfo.getBelongToRoleGroup(), StrUtil.COMMA).stream()
.map(Integer::valueOf).collect(Collectors.toList());
if (CollUtil.isNotEmpty(roleGroupIdList)) {
// 角色组对应角色
List<OauthRoleGroupInfo> roleGroupInfo = this.iOauthRoleGroupInfoDao.findByRoleGroupIdIn(roleGroupIdList);
roleGroupInfo.stream().map(OauthRoleGroupInfo::getRoleGroupName).forEach(roleStrSet::add);
}
ServiceAssert.isFalse(CollUtil.isEmpty(roleStrSet), "用户权限异常!");
return roleStrSet;
}
/**
* get by username
*/
public OauthUserInfo getByUserName(String userName) {
return this.iOauthUserInfoDao.getOne(userName);
}
}
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/sso?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
# mail:
# host: smtp.163.com
# port: 465
# username: 15122301381@163.com
# password: #自己的配置
# protocol: smtps
# rabbitmq:
# host: localhost
# port: 5672
# username: guest
# password: guest
# virtual-host: /
# #必须配置这个,生产者才会确认回调
# publisher-confirm-type: correlated
# publisher-returns: true
# #重要,手动开启消费者ACK,控制消息在MQ中的删除、重发
# listener:
# simple:
# acknowledge-mode: MANUAL
# 序列化时间的格式和时区
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
redis:
database: 7
host: 127.0.0.1
port: 6379
password: 123456
timeout: 10000
lettuce:
pool:
#连接池最大连接数(使用负数表示没有限制)默认8
max-active: 10
#连接池最大阻塞等待时间(使用负值表示没有限制)默认-1
max-wait: PT10S
#连接池最大空闲连接数(使用负值表示没有限制)默认8
max-idle: 3
#连接池最小空闲连接数(使用负值表示没有限制)默认0
min-idle: 1
jpa:
database: mysql
show-sql: true
#elasticsearch:
# host: 127.0.0.1
# port: 9200
# logback日志配置文件
logging:
config: classpath:logback.cfg.dev.xml
#mybatis:
# type-aliases-package: com.xbh.politemic.biz.*.domain
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# map-underscore-to-camel-case: true
# mapper-locations:
# - classpath:com/xbh/politemic/biz/*/mapper/*.xml
\ No newline at end of file
spring:
application:
name: authorization_server
profiles:
active: dev
server:
servlet:
context-path: /${spring.application.name}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="./.logs-project/" />
<!--控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<Pattern>%boldYellow(%thread) | %date{yyyy-MM-dd HH:mm:ss} | %highlight(%-5level) | %boldMagenta(%X{USER_ID}) | %boldGreen(%logger) | %msg%n</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>[%thread] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="debug">
<appender-ref ref="CONSOLE" />
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
</root>
</configuration>
\ No newline at end of file
package com.greatchn.authorization_server;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.greatchn.authorization_server.web.dao.IOauthFunctionInfoDao;
import com.greatchn.authorization_server.web.dao.IOauthRoleGroupInfoDao;
import com.greatchn.authorization_server.web.po.OauthRoleGroupInfo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
class AuthorizationServerApplicationTests {
@Resource
private IOauthFunctionInfoDao iOauthFunctionInfoDao;
@Resource
private IOauthRoleGroupInfoDao iOauthRoleGroupInfoDao;
@Test
void contextLoads() {
List<OauthRoleGroupInfo> list = this.iOauthRoleGroupInfoDao.findByBelongToUserGroupIdIn(CollUtil.list(Boolean.FALSE, 2, 3));
System.out.println(JSONUtil.toJsonPrettyStr(list));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.greatchn</groupId>
<artifactId>security_oauth_single_login</artifactId>
<version>1.0</version>
<name>root</name>
<packaging>pom</packaging>
<properties>
<spring-boot-version>2.3.7.RELEASE</spring-boot-version>
<java.version>1.8</java.version>
<jpa-version>2.6.7</jpa-version>
<mysql-version>8.0.32</mysql-version>
<lombok-version>1.18.24</lombok-version>
<hutool-version>5.7.22</hutool-version>
<oauth-version>2.2.5.RELEASE</oauth-version>
<apache-commons-pool2-version>2.8.1</apache-commons-pool2-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${jpa-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${apache-commons-pool2-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>${oauth-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot-version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.greatchn</groupId>
<artifactId>security_oauth_single_login</artifactId>
<version>1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>resource_server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>resource_server</name>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</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>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
package com.greatchn.resource_server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ResourceServerApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceServerApplication.class, args);
}
}
package com.greatchn.resource_server.config;
import com.greatchn.resource_server.constant.Constant;
import com.greatchn.resource_server.handler.AccessTokenConverter;
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.http.SessionCreationPolicy;
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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* @ResourceServerConfig: 资源服务配置
* @author: ZBoHang
* @time: 2023/2/28 17:34
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESIURCE_ID = "invoice_platfrom_resource_id";
@Resource
private AccessTokenConverter accessTokenConverter;
@Resource
private DataSource dataSource;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESIURCE_ID)
.tokenServices(tokenServices())
.stateless(Boolean.TRUE);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 资源服务器 除置换token意外 其它接口无需身份认证
.antMatchers("/sale/getInfo").authenticated()
.anyRequest()
.permitAll()
.and()
// 跨域
.cors().disable();
}
/**
* 令牌服务配置
*/
@Bean
public ResourceServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
// 配置令牌存储策略
services.setTokenStore(tokenStore());
// 增强转化
services.setTokenEnhancer(jwtAccessTokenConverter());
services.setClientDetailsService(jdbcClientDetailsService());
return services;
}
/**
* 令牌存储策略
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* 令牌转化
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(Constant.JWT_SECRET_KEY);
jwtAccessTokenConverter.setAccessTokenConverter(this.accessTokenConverter);
return jwtAccessTokenConverter;
}
/**
* 客户端信息
*/
@Bean
public JdbcClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(this.dataSource);
}
}
package com.greatchn.resource_server.constant;
/**
* @Constant: constant
* @author: ZBoHang
* @time: 2023/2/20 16:08
*/
public class Constant {
private Constant() {}
/**
* JWT 加密 密钥
*/
public static final String JWT_SECRET_KEY = "uiop";
}
package com.greatchn.resource_server.constant;
/**
* 结果集枚举
* @author: ZBoHang
* @time: 2023/2/8 10:54
*/
public enum ResultEnum {
SUCCESS(200, "请求成功"),
PARAMS_NONE_PASS(400, "参数校验未通过"),
NONE_AUTH(401, "本次访问没有权限"),
FAILURE(500, "服务器内部异常"),;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return this.code;
}
public String getMsg() {
return this.msg;
}
}
package com.greatchn.resource_server.handler;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @AccessTokenConverter: jwt 拓展
* @author: ZBoHang
* @time: 2023/3/2 15:15
*/
@Component
public class AccessTokenConverter extends DefaultAccessTokenConverter {
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
OAuth2Authentication authentication = super.extractAuthentication(map);
authentication.setDetails(map);
return authentication;
}
}
package com.greatchn.resource_server.util;
import com.greatchn.resource_server.constant.ResultEnum;
import lombok.Getter;
import java.io.Serializable;
/**
* @Description: ctrl统一返回
* @Author: zhengbohang
* @Date: 2021/10/3 10:43
*/
@Getter
public class Result implements Serializable {
private static final long serialVersionUID = -6166789405232241629L;
private Integer code;
private String msg;
private Object bean;
private Result() {
}
public static Result success() {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = ResultEnum.SUCCESS.getMsg();
return result;
}
public static Result success(String message) {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = message;
return result;
}
public static Result success(Object obj) {
Result result = new Result();
result.code = ResultEnum.SUCCESS.getCode();
result.msg = ResultEnum.SUCCESS.getMsg();
result.bean = obj;
return result;
}
public static Result failure() {
Result result = new Result();
result.code = ResultEnum.FAILURE.getCode();
result.msg = ResultEnum.FAILURE.getMsg();
return result;
}
public static Result failure(String message) {
Result result = new Result();
result.code = ResultEnum.FAILURE.getCode();
result.msg = message;
return result;
}
public static Result failure(Integer code, String msg) {
Result result = new Result();
result.code = code;
result.msg = msg;
return result;
}
public static Result noneAuth() {
Result result = new Result();
result.code = ResultEnum.NONE_AUTH.getCode();
result.msg = ResultEnum.NONE_AUTH.getMsg();
return result;
}
}
package com.greatchn.resource_server.web.controller;
import cn.hutool.json.JSONUtil;
import com.greatchn.resource_server.util.Result;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* @SaleController: 销售
* @author: ZBoHang
* @time: 2023/2/28 17:46
*/
@RequestMapping("/sale")
@RestController
public class SaleController {
/**
* get info
*/
@PostMapping("/getInfo")
public Result getInfo(Principal principal, Authentication authentication) {
Authentication localAuth = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails details = ((OAuth2AuthenticationDetails) localAuth.getDetails());
System.out.println(JSONUtil.toJsonPrettyStr(details.getDecodedDetails()));
return Result.success(authentication);
}
/**
* get info
*/
@PostMapping("/check")
public Result check(String name) {
return Result.success(name);
}
}
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/sso?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
# mail:
# host: smtp.163.com
# port: 465
# username: 15122301381@163.com
# password: #自己的配置
# protocol: smtps
# rabbitmq:
# host: localhost
# port: 5672
# username: guest
# password: guest
# virtual-host: /
# #必须配置这个,生产者才会确认回调
# publisher-confirm-type: correlated
# publisher-returns: true
# #重要,手动开启消费者ACK,控制消息在MQ中的删除、重发
# listener:
# simple:
# acknowledge-mode: MANUAL
# 序列化时间的格式和时区
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
redis:
database: 7
host: 127.0.0.1
port: 6379
password: 123456
timeout: 10000
lettuce:
pool:
#连接池最大连接数(使用负数表示没有限制)默认8
max-active: 10
#连接池最大阻塞等待时间(使用负值表示没有限制)默认-1
max-wait: PT10S
#连接池最大空闲连接数(使用负值表示没有限制)默认8
max-idle: 3
#连接池最小空闲连接数(使用负值表示没有限制)默认0
min-idle: 1
jpa:
database: mysql
show-sql: true
#elasticsearch:
# host: 127.0.0.1
# port: 9200
# logback日志配置文件
logging:
config: classpath:logback.cfg.dev.xml
#mybatis:
# type-aliases-package: com.xbh.politemic.biz.*.domain
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# map-underscore-to-camel-case: true
# mapper-locations:
# - classpath:com/xbh/politemic/biz/*/mapper/*.xml
\ No newline at end of file
spring:
application:
name: resource_server
profiles:
active: dev
server:
servlet:
context-path: /${spring.application.name}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="./.logs-project/" />
<!--控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<Pattern>%boldYellow(%thread) | %date{yyyy-MM-dd HH:mm:ss} | %highlight(%-5level) | %boldMagenta(%X{USER_ID}) | %boldGreen(%logger) | %msg%n</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>[%thread] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="debug">
<appender-ref ref="CONSOLE" />
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
</root>
</configuration>
\ No newline at end of file
package com.greatchn.resource_server;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ResourceServerApplicationTests {
@Test
void contextLoads() {
}
}
/*
Navicat Premium Data Transfer
Source Server : 本地_v8
Source Server Type : MySQL
Source Server Version : 80020
Source Host : localhost:3306
Source Schema : sso
Target Server Type : MySQL
Target Server Version : 80020
File Encoding : 65001
Date: 08/03/2023 15:25:56
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端ID',
`resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端密钥',
`scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '授权类型',
`web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`access_token_validity` int(0) NULL DEFAULT NULL COMMENT 'access_token的有效时间',
`refresh_token_validity` int(0) NULL DEFAULT NULL COMMENT 'refresh_token的有效时间',
`additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否允许自动授权',
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('finance_shared_client', 'finance_shared_resource_id', 'finance_shared_client_secret', 'ALL', 'client_credentials,refresh_token', NULL, NULL, 1800, NULL, NULL, 'true');
INSERT INTO `oauth_client_details` VALUES ('invoice_platfrom_client', 'invoice_platfrom_resource_id', 'invoice_platfrom_client_secret', 'ALL', 'client_credentials,refresh_token', NULL, NULL, 1800, NULL, NULL, 'true');
INSERT INTO `oauth_client_details` VALUES ('sale_client', 'sale_resource_id', 'sale_client_secret', 'ALL', 'client_credentials,refresh_token', NULL, NULL, 1800, NULL, NULL, 'true');
-- ----------------------------
-- Table structure for oauth_config
-- ----------------------------
DROP TABLE IF EXISTS `oauth_config`;
CREATE TABLE `oauth_config` (
`key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'k',
`value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'v',
`desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`state` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态 Y-有效 N-无效',
PRIMARY KEY (`key`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_config
-- ----------------------------
INSERT INTO `oauth_config` VALUES ('no_authentication_path_str', '/login/login', '不需要登录的路径合集 多个用 , 分隔', 'Y');
-- ----------------------------
-- Table structure for oauth_function_info
-- ----------------------------
DROP TABLE IF EXISTS `oauth_function_info`;
CREATE TABLE `oauth_function_info` (
`function_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '功能id',
`function_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能名称',
`desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`state` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态 Y-有效 N-无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`function_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_function_info
-- ----------------------------
INSERT INTO `oauth_function_info` VALUES (1, '/sale', '销售', 'Y', '2023-02-28 09:57:25');
INSERT INTO `oauth_function_info` VALUES (2, '/paper/ticket', '开纸质票', 'Y', '2023-02-28 09:57:50');
INSERT INTO `oauth_function_info` VALUES (3, '/telex/ticket', '开电子票', 'Y', '2023-02-28 09:58:56');
INSERT INTO `oauth_function_info` VALUES (4, '/generate/authorization/number', '生成授权号', 'Y', '2023-02-28 09:58:59');
INSERT INTO `oauth_function_info` VALUES (5, '/bonus/points', '赠送积分', 'Y', '2023-02-28 09:59:04');
INSERT INTO `oauth_function_info` VALUES (6, 'virtual/billing', '虚拟开票', 'Y', '2023-02-28 09:59:08');
INSERT INTO `oauth_function_info` VALUES (7, '/full/telex/ticket', '全电票', 'Y', '2023-02-28 09:59:12');
INSERT INTO `oauth_function_info` VALUES (8, '/reconciliation', '对账', 'Y', '2023-02-28 09:59:15');
INSERT INTO `oauth_function_info` VALUES (9, '/accounting', '账目统计', 'Y', '2023-02-28 09:59:19');
INSERT INTO `oauth_function_info` VALUES (10, '/bookkeeping', '记账', 'Y', '2023-02-28 09:59:21');
-- ----------------------------
-- Table structure for oauth_role_function_connection
-- ----------------------------
DROP TABLE IF EXISTS `oauth_role_function_connection`;
CREATE TABLE `oauth_role_function_connection` (
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_group_id` int(0) NULL DEFAULT NULL COMMENT '角色组id',
`belong_to_user_group_id` int(0) NULL DEFAULT NULL COMMENT '所属用户组id',
`function_id` int(0) NULL DEFAULT NULL COMMENT '功能id',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_role_function_connection
-- ----------------------------
INSERT INTO `oauth_role_function_connection` VALUES (1, 1, 1, 1, '2023-02-28 10:08:17');
INSERT INTO `oauth_role_function_connection` VALUES (2, 1, 1, 2, '2023-02-28 10:12:27');
INSERT INTO `oauth_role_function_connection` VALUES (3, 1, 1, 3, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (4, 1, 1, 4, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (5, 1, 1, 5, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (6, 1, 1, 6, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (7, 1, 1, 7, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (8, 1, 1, 8, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (9, 1, 1, 9, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (10, 1, 1, 10, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (11, 2, 2, 1, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (12, 2, 2, 2, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (13, 2, 2, 3, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (14, 2, 2, 4, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (15, 2, 2, 5, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (16, 2, 2, 6, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (17, 2, 2, 7, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (18, 3, 3, 8, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (19, 3, 3, 9, '2023-02-28 10:12:29');
INSERT INTO `oauth_role_function_connection` VALUES (20, 3, 3, 10, '2023-02-28 10:12:29');
-- ----------------------------
-- Table structure for oauth_role_group_info
-- ----------------------------
DROP TABLE IF EXISTS `oauth_role_group_info`;
CREATE TABLE `oauth_role_group_info` (
`role_group_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '角色组id',
`role_group_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色组名称',
`belong_to_user_group_id` int(0) NOT NULL COMMENT '所属用户组id',
`perent_id` int(0) NULL DEFAULT NULL COMMENT '父级id 顶级为-1',
`desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`state` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态 Y-有效 N-无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`role_group_id`, `belong_to_user_group_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_role_group_info
-- ----------------------------
INSERT INTO `oauth_role_group_info` VALUES (1, 'SUPER_ADMIN', 1, -1, NULL, 'Y', '2023-02-28 09:47:10');
INSERT INTO `oauth_role_group_info` VALUES (2, 'USER_ADMIN', 2, 1, NULL, 'Y', '2023-02-28 09:50:13');
INSERT INTO `oauth_role_group_info` VALUES (3, 'GENERAL_ADMIN', 3, 1, NULL, 'Y', '2023-02-28 09:54:02');
-- ----------------------------
-- Table structure for oauth_user_group_info
-- ----------------------------
DROP TABLE IF EXISTS `oauth_user_group_info`;
CREATE TABLE `oauth_user_group_info` (
`user_group_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '用户组id',
`user_group_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户组名称',
`parent_id` int(0) NULL DEFAULT NULL COMMENT '父级id 顶级为-1',
`desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`state` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态 Y-有效 N-无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`user_group_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_user_group_info
-- ----------------------------
INSERT INTO `oauth_user_group_info` VALUES (1, '系统根用户组', -1, '最顶层', 'Y', '2023-02-28 09:38:35');
INSERT INTO `oauth_user_group_info` VALUES (2, '用户管理组', 1, NULL, 'Y', '2023-02-28 09:41:41');
INSERT INTO `oauth_user_group_info` VALUES (3, '普通管理员', 1, NULL, 'Y', '2023-02-28 09:49:25');
-- ----------------------------
-- Table structure for oauth_user_info
-- ----------------------------
DROP TABLE IF EXISTS `oauth_user_info`;
CREATE TABLE `oauth_user_info` (
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`belong_to_user_group` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属用户组',
`belong_to_role_group` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属角色组',
`state` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态 Y-有效 N-无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`user_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of oauth_user_info
-- ----------------------------
INSERT INTO `oauth_user_info` VALUES ('aaa', '123456', '2', '2', 'Y', '2023-03-03 09:17:13');
INSERT INTO `oauth_user_info` VALUES ('root', '123456', '1', '1', 'Y', '2023-02-28 09:31:44');
SET FOREIGN_KEY_CHECKS = 1;
B文件夹 PATH 列表 B文件夹 PATH 列表
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment