feat: 初始化

This commit is contained in:
张云杰 2024-04-09 11:34:46 +08:00
commit 39f3acc15f
3209 changed files with 253442 additions and 0 deletions

362
.gitignore vendored Normal file
View File

@ -0,0 +1,362 @@
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### SublimeText template
# Cache files for Sublime Text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# Workspace files are user-specific
*.sublime-workspace
# Project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using Sublime Text
# *.sublime-project
# SFTP configuration file
sftp-config.json
sftp-config-alt*.json
# Package control specific files
Package Control.last-run
Package Control.ca-list
Package Control.ca-bundle
Package Control.system-ca-bundle
Package Control.cache/
Package Control.ca-certs/
Package Control.merged-ca-bundle
Package Control.user-ca-bundle
oscrypto-ca-bundle.crt
bh_unicode_properties.cache
# Sublime-github package stores a github token in this file
# https://packagecontrol.io/packages/sublime-github
GitHub.sublime-settings
### Node template
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Next.js build output
.next
### Java template
# Compiled class file
*.class
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Eclipse template
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Vue template
# gitignore template for Vue.js projects
#
# Recommended template: Node.gitignore
# TODO: where does this rule come from?
docs/_book
### SVN template
.svn/
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Vue template
# gitignore template for Vue.js projects
#
# Recommended template: Node.gitignore
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.project
.settings
.sts4-cache
### IntelliJ IDEA ###
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
/upload/
rebel.xml

1
Readme.md Normal file
View File

@ -0,0 +1 @@
### 校园旧版

View File

@ -0,0 +1,27 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>edu-auth</artifactId>
<groupId>com.yida.data.auth</groupId>
<version>2.2-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>edu-auth-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-core</artifactId>
<version>2.2-RELEASE</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,20 @@
package com.yida.data.auth;
import com.yida.data.common.core.entity.constant.FebsServerConstant;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = FebsServerConstant.EDU_AUTH, contextId = "authServiceClient",
fallbackFactory = RemoteAuthServiceFallback.class)
public interface RemoteAuthService {
/**
* 撤销认证
*
* @param userName
* @param clientId
*/
@GetMapping("/in/security/revokeApproval")
void revokeApproval(@RequestParam("userName") String userName, @RequestParam("clientId") String clientId);
}

View File

@ -0,0 +1,34 @@
package com.yida.data.auth;
import com.yida.data.common.core.annotation.Fallback;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
/**
* RemoteAuthService fallback处理类
*
* @author ZYJ
* @date 2022/8/26
*/
@Slf4j
@Fallback
public class RemoteAuthServiceFallback implements FallbackFactory<RemoteAuthService> {
@Override
public RemoteAuthService create(Throwable throwable) {
log.error("RemoteAuthService fallback reason:{}", throwable.getMessage());
return new RemoteAuthService() {
/**
* 撤销认证
*
* @param userName
* @param clientId
*/
@Override
public void revokeApproval(String userName, String clientId) {
}
};
}
}

View File

@ -0,0 +1,3 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yida.data.auth.RemoteAuthServiceFallback

View File

@ -0,0 +1,109 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>edu-auth</artifactId>
<groupId>com.yida.data.auth</groupId>
<version>2.2-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>edu-auth-biz</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-redis-starter</artifactId>
<version>${febs-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-datasource-starter</artifactId>
<version>${febs-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-doc-starter</artifactId>
<version>${febs-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-security-starter</artifactId>
<version>${febs-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha.version}</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.xkcoding</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<version>${justauth.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.yida.data.user</groupId>
<artifactId>edu-user-api</artifactId>
<version>${febs-cloud.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yida.data.system</groupId>
<artifactId>febs-server-system-api</artifactId>
<version>${febs-cloud.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yida.data.common</groupId>
<artifactId>edu-common</artifactId>
<version>${febs-cloud.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-log-starter</artifactId>
<version>${febs-cloud.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<outputDirectory>../../febs-jar</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,27 @@
package com.yida.data.auth;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import cc.mrbird.febs.common.security.starter.annotation.EnableFebsCloudResourceServer;
/**
* @author MrBird
*/
@SpringBootApplication
@EnableRedisHttpSession
@EnableFebsCloudResourceServer
@MapperScan("com.yida.data.auth.mapper")
@EnableFeignClients(basePackages = "com.yida.data")
public class EduAuthApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(EduAuthApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}

View File

@ -0,0 +1,124 @@
package com.yida.data.auth.configure;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
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.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
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 org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import java.util.UUID;
import com.yida.data.auth.properties.FebsAuthProperties;
import com.yida.data.auth.service.impl.RedisAuthenticationCodeService;
import com.yida.data.auth.service.impl.RedisClientDetailsService;
import com.yida.data.auth.translator.FebsWebResponseExceptionTranslator;
import lombok.RequiredArgsConstructor;
/**
* 认证服务器配置
*/
@Configuration
@EnableAuthorizationServer
@RequiredArgsConstructor
public class FebsAuthorizationServerConfigure extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailService;
private final PasswordEncoder passwordEncoder;
private final FebsWebResponseExceptionTranslator exceptionTranslator;
private final FebsAuthProperties properties;
private final RedisAuthenticationCodeService authenticationCodeService;
private final RedisClientDetailsService redisClientDetailsService;
private final RedisConnectionFactory redisConnectionFactory;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(redisClientDetailsService);
}
@Override
@SuppressWarnings("unchecked")
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore())
.userDetailsService(userDetailService)
.authorizationCodeServices(authenticationCodeService)
.authenticationManager(authenticationManager)
.exceptionTranslator(exceptionTranslator);
if (properties.getEnableJwt()) {
endpoints.accessTokenConverter(jwtAccessTokenConverter());
}
}
@Bean
public TokenStore tokenStore() {
if (properties.getEnableJwt()) {
return new JwtTokenStore(jwtAccessTokenConverter());
} else {
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
// 解决每次生成的 token都一样的问题
redisTokenStore.setAuthenticationKeyGenerator(oAuth2Authentication -> UUID.randomUUID().toString());
return redisTokenStore;
}
}
@Bean
public TokenApprovalStore tokenApprovalStore(TokenStore tokenStore){
TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
tokenApprovalStore.setTokenStore(tokenStore);
return tokenApprovalStore;
}
@Bean
@Primary
public DefaultTokenServices defaultTokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(redisClientDetailsService);
return tokenServices;
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
DefaultAccessTokenConverter defaultAccessTokenConverter = (DefaultAccessTokenConverter) accessTokenConverter.getAccessTokenConverter();
DefaultUserAuthenticationConverter userAuthenticationConverter = new DefaultUserAuthenticationConverter();
userAuthenticationConverter.setUserDetailsService(userDetailService);
defaultAccessTokenConverter.setUserTokenConverter(userAuthenticationConverter);
accessTokenConverter.setSigningKey(properties.getJwtAccessKey());
return accessTokenConverter;
}
@Bean
public ResourceOwnerPasswordTokenGranter resourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, OAuth2RequestFactory oAuth2RequestFactory) {
DefaultTokenServices defaultTokenServices = defaultTokenServices();
if (properties.getEnableJwt()) {
defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
}
return new ResourceOwnerPasswordTokenGranter(authenticationManager, defaultTokenServices, redisClientDetailsService, oAuth2RequestFactory);
}
@Bean
public DefaultOAuth2RequestFactory oAuth2RequestFactory() {
return new DefaultOAuth2RequestFactory(redisClientDetailsService);
}
}

View File

@ -0,0 +1,65 @@
package com.yida.data.auth.configure;
import com.yida.data.auth.handler.FebsWebLoginFailureHandler;
import com.yida.data.auth.handler.FebsWebLoginSuccessHandler;
import com.yida.data.auth.filter.ValidateCodeFilter;
import com.yida.data.common.core.entity.constant.EndpointConstant;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* WebSecurity配置
*
* @author MrBird
*/
@Order(2)
@EnableWebSecurity
@RequiredArgsConstructor
public class FebsSecurityConfigure extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailService;
private final ValidateCodeFilter validateCodeFilter;
private final PasswordEncoder passwordEncoder;
private final FebsWebLoginSuccessHandler successHandler;
private final FebsWebLoginFailureHandler failureHandler;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.requestMatchers()
.antMatchers(EndpointConstant.OAUTH_ALL, EndpointConstant.LOGIN)
.and()
.authorizeRequests()
.antMatchers(EndpointConstant.OAUTH_ALL).authenticated()
.and()
.formLogin()
.loginPage(EndpointConstant.LOGIN)
.loginProcessingUrl(EndpointConstant.LOGIN)
.successHandler(successHandler)
.failureHandler(failureHandler)
.permitAll()
.and().csrf().disable()
.httpBasic().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder);
}
}

View File

@ -0,0 +1,97 @@
package com.yida.data.auth.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import com.yida.data.auth.service.OauthClientDetailsService;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.QueryRequest;
import com.yida.data.common.core.entity.auth.OauthClientDetails;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author Yuuki
*/
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("client")
public class OauthClientDetailsController {
private final OauthClientDetailsService oauthClientDetailsService;
@GetMapping("check/{clientId}")
public boolean checkUserName(@NotBlank(message = "{required}") @PathVariable String clientId) {
OauthClientDetails client = this.oauthClientDetailsService.findById(clientId);
return client == null;
}
@GetMapping("secret/{clientId}")
@PreAuthorize("hasAuthority('client:decrypt')")
public FebsResponse getOriginClientSecret(@NotBlank(message = "{required}") @PathVariable String clientId) {
OauthClientDetails client = this.oauthClientDetailsService.findById(clientId);
String origin = client != null ? client.getOriginSecret() : StringUtils.EMPTY;
return new FebsResponse().data(origin);
}
@GetMapping
@PreAuthorize("hasAuthority('client:view')")
public FebsResponse oauthCliendetailsList(QueryRequest request, OauthClientDetails oAuthClientDetails) {
Map<String, Object> dataTable = FebsUtil.getDataTable(this.oauthClientDetailsService.findOauthClientDetails(request, oAuthClientDetails));
return new FebsResponse().data(dataTable);
}
@PostMapping
@PreAuthorize("hasAuthority('client:add')")
public void addOauthCliendetails(@Valid OauthClientDetails oAuthClientDetails) throws FebsException {
try {
this.oauthClientDetailsService.createOauthClientDetails(oAuthClientDetails);
} catch (Exception e) {
String message = "新增客户端失败";
log.error(message, e);
throw new FebsException(message);
}
}
@DeleteMapping
@PreAuthorize("hasAuthority('client:delete')")
public void deleteOauthCliendetails(@NotBlank(message = "{required}") String clientIds) throws FebsException {
try {
this.oauthClientDetailsService.deleteOauthClientDetails(clientIds);
} catch (Exception e) {
String message = "删除客户端失败";
log.error(message, e);
throw new FebsException(message);
}
}
@PutMapping
@PreAuthorize("hasAuthority('client:update')")
public void updateOauthCliendetails(@Valid OauthClientDetails oAuthClientDetails) throws FebsException {
try {
this.oauthClientDetailsService.updateOauthClientDetails(oAuthClientDetails);
} catch (Exception e) {
String message = "修改客户端失败";
log.error(message, e);
throw new FebsException(message);
}
}
}

View File

@ -0,0 +1,70 @@
package com.yida.data.auth.controller;
import com.yida.data.auth.manager.UserManager;
import com.yida.data.auth.service.SecurityService;
import com.yida.data.auth.service.ValidateCodeService;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.exception.ValidateCodeException;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
/**
* @author MrBird
*/
@Controller
@RequiredArgsConstructor
public class SecurityController {
private final ValidateCodeService validateCodeService;
private final SecurityService securityService;
private final UserManager userManager;
private final ConsumerTokenServices consumerTokenServices;
@ResponseBody
@GetMapping("user")
public Principal currentUser(Principal principal) {
return principal;
}
@ResponseBody
@GetMapping("captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException, ValidateCodeException {
validateCodeService.create(request, response);
}
@RequestMapping("login")
public String login() {
return "login";
}
@RequestMapping("test")
public String test() {
return "test";
}
@ResponseBody
@DeleteMapping("signout")
public FebsResponse signout(HttpServletRequest request, @RequestHeader("Authorization") String token) {
token = StringUtils.replace(token, "bearer ", StringConstant.EMPTY);
consumerTokenServices.revokeToken(token);
return new FebsResponse().message("signout");
}
@ApiOperation("获取学校负责人登录信息")
@ResponseBody
@GetMapping("/inSchool")
public FebsResponse inSchool(Long schoolId) {
return new FebsResponse().data(securityService.getSchoolToken(schoolId));
}
}

View File

@ -0,0 +1,225 @@
package com.yida.data.auth.controller;
import com.yida.data.auth.entity.BindUser;
import com.yida.data.auth.service.SocialLoginService;
import com.yida.data.common.core.common.ModuleName;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.UserConnection;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.log.annotation.OperationLog;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author MrBird
*/
@Slf4j
@Controller
@RefreshScope
@RequiredArgsConstructor
@RequestMapping("social")
public class SocialLoginController {
private static final String TYPE_LOGIN = "login";
private static final String TYPE_BIND = "bind";
private final SocialLoginService socialLoginService;
@Value("${febs.frontUrl}")
private String frontUrl;
/**
* 登录
*
* @param oauthType 第三方登录类型
* @param response response
*/
@ResponseBody
@GetMapping("/login/{oauthType}/{type}")
public void renderAuth(@PathVariable String oauthType, @PathVariable String type, HttpServletResponse response)
throws IOException, FebsException {
AuthRequest authRequest = socialLoginService.renderAuth(oauthType);
response.sendRedirect(
authRequest.authorize(oauthType + StringConstant.DOUBLE_COLON + AuthStateUtils.createState()) + "::"
+ type);
}
/**
* 登录成功后的回调
*
* @param oauthType 第三方登录类型
* @param callback 携带返回的信息
* @return String
*/
@GetMapping("/{oauthType}/callback")
public String login(@PathVariable String oauthType, AuthCallback callback, String state, Model model) {
try {
FebsResponse febsResponse = null;
String type = StringUtils.substringAfterLast(state, StringConstant.DOUBLE_COLON);
if (StringUtils.equals(type, TYPE_BIND)) {
febsResponse = socialLoginService.resolveBind(oauthType, callback);
} else {
febsResponse = socialLoginService.resolveLogin(oauthType, callback);
}
model.addAttribute("response", febsResponse);
model.addAttribute("frontUrl", frontUrl);
return "result";
} catch (Exception e) {
String errorMessage = FebsUtil.containChinese(e.getMessage()) ? e.getMessage() : "第三方登录失败";
model.addAttribute("error", e.getMessage());
return "fail";
}
}
/**
* 绑定并登录
*
* @param bindUser bindUser
* @param authUser authUser
* @return FebsResponse
*/
@ResponseBody
@PostMapping("bind/login")
public FebsResponse bindLogin(@Valid BindUser bindUser, AuthUser authUser) throws FebsException {
OAuth2AccessToken oAuth2AccessToken = this.socialLoginService.bindLogin(bindUser, authUser);
return new FebsResponse().data(oAuth2AccessToken);
}
/**
* 注册并登录
*
* @param registUser registUser
* @param authUser authUser
* @return FebsResponse
*/
@ResponseBody
@PostMapping("sign/login")
public FebsResponse signLogin(@Valid BindUser registUser, AuthUser authUser) throws FebsException {
OAuth2AccessToken oAuth2AccessToken = this.socialLoginService.signLogin(registUser, authUser);
return new FebsResponse().data(oAuth2AccessToken);
}
/**
* 绑定
*
* @param bindUser bindUser
* @param authUser authUser
*/
@ResponseBody
@PostMapping("bind")
public void bind(BindUser bindUser, AuthUser authUser) throws FebsException {
this.socialLoginService.bind(bindUser, authUser);
}
/**
* 解绑
*
* @param bindUser bindUser
* @param oauthType oauthType
*/
@ResponseBody
@DeleteMapping("unbind")
public void unbind(BindUser bindUser, String oauthType) throws FebsException {
this.socialLoginService.unbind(bindUser, oauthType);
}
/**
* 根据用户名获取绑定关系
*
* @param username 用户名
* @return FebsResponse
*/
@ResponseBody
@GetMapping("connections/{username}")
public FebsResponse findUserConnections(@NotBlank(message = "{required}") @PathVariable String username) {
List<UserConnection> userConnections = this.socialLoginService.findUserConnections(username);
return new FebsResponse().data(userConnections);
}
/**
* 企业微信用户授权登录回调
*/
@ResponseBody
@GetMapping("qywx/login")
@OperationLog(module = ModuleName.AUTH, methods = "企业微信登录")
public FebsResponse qywxLogin(String code, String state, String corpId,
@ApiParam("0-教师1-家长") Integer type) {
return new FebsResponse().data(socialLoginService.qywxLogin(code, state, corpId, type));
}
@ResponseBody
@GetMapping("app/login")
//@OperationLog(module = ModuleName.AUTH, methods = "app登录")
public FebsResponse appLogin(@ApiParam("区域idapp") String areaId,
@ApiParam("学校Id") Long schoolId,
@ApiParam("手机号") String mobile,
@ApiParam("app用户id") String userId,
@ApiParam("0-教师1-家长") Integer type) {
return new FebsResponse().data(socialLoginService.appLogin(areaId, schoolId, mobile, userId, type));
}
@ResponseBody
@GetMapping("wxpublic/login")
//@OperationLog(module = ModuleName.AUTH, methods = "app登录")
public FebsResponse wxpublicLogin(String code, String appId,
@ApiParam("0-教师1-家长") Integer type,
Long schoolId, String mobile) {
return new FebsResponse().data(socialLoginService.wxpublicLogin(code, appId, type, schoolId, mobile));
}
/**
* h5登录
*
* @param schoolId 学校Id
* @param mobile 手机号
* @param type 0-教师1-家长
* @return com.yida.data.common.core.entity.FebsResponse
* @author ZYJ
* @date 2022/9/19 17:25
*/
@ResponseBody
@GetMapping("h5/login")
public FebsResponse h5Login(@ApiParam("学校Id") Long schoolId, @ApiParam("手机号") String mobile,
@ApiParam("0-教师1-家长") Integer type) {
return new FebsResponse().data(socialLoginService.h5Login(schoolId, mobile, type));
}
@ResponseBody
@ApiOperation("检查openId状态")
@GetMapping("smart/checkOpenId")
public ResultBean<Map<String, Object>> checkOpenId(@RequestParam @ApiParam(value = "微信公众号授权code", required = true) String code,
@RequestParam @ApiParam(value = "学校id(链接上附带)", required = true) Long deptId) {
return ResultBean.buildSuccess(socialLoginService.checkOpenId(code, deptId));
}
@ResponseBody
@ApiOperation("智慧迎新学生端登录接口")
@GetMapping("wxPublic/welcome/login")
public FebsResponse wxPublicLogin(@RequestParam @ApiParam(value = "微信openId", required = true) String openId,
@RequestParam @ApiParam(value = "学校id(链接上附带)", required = true) Long deptId) {
return new FebsResponse().data(socialLoginService.wxPublicLogin(openId, deptId));
}
}

View File

@ -0,0 +1,37 @@
package com.yida.data.auth.controller.in;
import com.yida.data.auth.service.impl.RedisClientDetailsService;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/in/security")
@RestController
@RequiredArgsConstructor
public class InSecurityController {
private final TokenApprovalStore tokenApprovalStore;
private final RedisClientDetailsService redisClientDetailsService;
@ApiOperation("撤销认证")
@GetMapping("/revokeApproval")
public void revokeApproval(String userName, String clientId) {
ClientDetails client = redisClientDetailsService.loadClientByClientId(clientId);
List<Approval> approvals = new ArrayList<Approval>();
for (String scope : client.getScope()) {
approvals.add(new Approval(userName, clientId, scope, new Date(), ApprovalStatus.APPROVED));
}
tokenApprovalStore.revokeApprovals(approvals);
}
}

View File

@ -0,0 +1,20 @@
package com.yida.data.auth.entity;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* @author MrBird
*/
@Data
public class BindUser implements Serializable {
private static final long serialVersionUID = -3890998115990166651L;
@NotBlank(message = "{required}")
private String bindUsername;
@NotBlank(message = "{required}")
private String bindPassword;
}

View File

@ -0,0 +1,65 @@
package com.yida.data.auth.filter;
import com.yida.data.auth.service.ValidateCodeService;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.constant.EndpointConstant;
import com.yida.data.common.core.entity.constant.GrantTypeConstant;
import com.yida.data.common.core.entity.constant.ParamsConstant;
import com.yida.data.common.core.exception.ValidateCodeException;
import com.yida.data.common.core.utils.FebsUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Nonnull;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 验证码过滤器
*
* @author MrBird
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ValidateCodeFilter extends OncePerRequestFilter {
private final ValidateCodeService validateCodeService;
@Override
protected void doFilterInternal(@Nonnull HttpServletRequest httpServletRequest, @Nonnull HttpServletResponse httpServletResponse,
@Nonnull FilterChain filterChain) throws ServletException, IOException {
String header = httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION);
RequestMatcher matcher = new AntPathRequestMatcher(EndpointConstant.OAUTH_TOKEN, HttpMethod.POST.toString());
if (matcher.matches(httpServletRequest)
&& StringUtils.equalsIgnoreCase(httpServletRequest.getParameter(ParamsConstant.GRANT_TYPE), GrantTypeConstant.PASSWORD)) {
try {
validateCode(httpServletRequest);
filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch (Exception e) {
FebsResponse febsResponse = new FebsResponse();
FebsUtil.makeFailureResponse(httpServletResponse, febsResponse.message(e.getMessage()));
log.error(e.getMessage(), e);
}
} else {
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
private void validateCode(HttpServletRequest httpServletRequest) throws ValidateCodeException {
String code = httpServletRequest.getParameter(ParamsConstant.VALIDATE_CODE_CODE);
String key = httpServletRequest.getParameter(ParamsConstant.VALIDATE_CODE_KEY);
validateCodeService.check(key, code);
}
}

View File

@ -0,0 +1,33 @@
package com.yida.data.auth.handler;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.utils.FebsUtil;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author MrBird
*/
@Component
public class FebsWebLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException exception) throws IOException {
String message;
if (exception instanceof BadCredentialsException) {
message = "用户名或密码错误!";
} else if (exception instanceof LockedException) {
message = "用户已被锁定!";
} else {
message = "认证失败,请联系网站管理员!";
}
FebsResponse febsResponse = new FebsResponse().message(message);
FebsUtil.makeFailureResponse(httpServletResponse, febsResponse);
}
}

View File

@ -0,0 +1,53 @@
package com.yida.data.auth.handler;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.utils.FebsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @author MrBird
*/
@Slf4j
@Component
public class FebsWebLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private final RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
SavedRequest savedRequest = requestCache.getRequest(request, response);
HttpSession session = request.getSession(false);
if (session != null) {
Object attribute = session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
log.info("跳转到登录页的地址为: {}", attribute);
}
if (FebsUtil.isAjaxRequest(request)) {
FebsResponse data = new FebsResponse();
if (savedRequest == null) {
FebsUtil.makeFailureResponse(response, data.message("请通过授权码模式跳转到该页面"));
return;
}
data.data(savedRequest.getRedirectUrl());
FebsUtil.makeSuccessResponse(response, data);
} else {
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
return;
}
clearAuthenticationAttributes(request);
getRedirectStrategy().sendRedirect(request, response, savedRequest.getRedirectUrl());
}
}
}

View File

@ -0,0 +1,174 @@
package com.yida.data.auth.manager;
import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.auth.mapper.EduUserLogoMapper;
import com.yida.data.auth.mapper.MenuMapper;
import com.yida.data.auth.mapper.RoleMapper;
import com.yida.data.auth.mapper.UserMapper;
import com.yida.data.auth.mapper.UserMenuMapper;
import com.yida.data.auth.mapper.UserRoleMapper;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.EduUserLogo;
import com.yida.data.common.core.entity.system.Menu;
import com.yida.data.common.core.entity.system.Role;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.entity.system.SystemUserMenu;
import com.yida.data.common.core.entity.system.UserRole;
import com.yida.data.common.service.CommonService;
import com.yida.data.user.feign.RemoteTeacherService;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* 用户业务逻辑
*
* @author MrBird
*/
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserManager {
private final UserMapper userMapper;
private final EduUserLogoMapper eduUserLogoMapper;
private final MenuMapper menuMapper;
private final RoleMapper roleMapper;
private final UserRoleMapper userRoleMapper;
private final UserMenuMapper userMenuMapper;
private final RemoteTeacherService remoteTeacherService;
private final RedisService redisService;
private final CommonService commonService;
/**
* 通过用户名查询用户信息
*
* @param username 用户名
* @return 用户
*/
public SystemUser findByName(String username) {
Object deptO = redisService.hget(CachePrefixConstant.USER_LOGIN_DEPT, username);
SystemUser user = userMapper.findByName(username);
if (user != null) {
if (deptO != null) {
Long deptId = Long.valueOf(deptO.toString());
Dept dept = commonService.getDept(deptId);
user.setDeptId(dept.getDeptId());
user.setDeptName(dept.getDeptName());
user.setDeptType(dept.getDeptType());
}
user.setUserLogo(
eduUserLogoMapper.selectOne(Wrappers.<EduUserLogo>lambdaQuery().eq(EduUserLogo::getUserId, user.getUserId())));
}
return user;
}
/**
* 通过用户名查询用户权限串
*
* @param username 用户名
* @return 权限
*/
public List<String> findUserPermissions(String username) {
// 获取角色权限
List<String> menus = menuMapper.findUserPermissions(username);
// 获取用户权限
List<SystemUserMenu> userPermissions = userMenuMapper.findUserPermissions(username);
// 过滤
if (CollUtil.isNotEmpty(userPermissions)) {
menus.addAll(
userPermissions.stream().filter(x -> x.getType() == 0).map(SystemUserMenu::getPerms).filter(StrUtil::isNotBlank)
.collect(Collectors.toList()));
List<String> excludePerms = userPermissions.stream().filter(x -> x.getType() == 1).map(SystemUserMenu::getPerms)
.filter(StrUtil::isNotBlank).collect(Collectors.toList());
if (CollUtil.isNotEmpty(excludePerms)) {
menus = menus.stream().filter(x -> !excludePerms.contains(x)).collect(Collectors.toList());
}
}
// 只返回串
return menus;
}
/**
* 注册用户
*
* @param username username
* @param password password
* @return SystemUser SystemUser
*/
@Transactional(rollbackFor = Exception.class)
public SystemUser registUser(String username, String password) {
SystemUser systemUser = new SystemUser();
systemUser.setUsername(username);
systemUser.setPassword(password);
systemUser.setStatus(SystemUser.STATUS_VALID);
systemUser.setSex(SystemUser.SEX_UNKNOW);
systemUser.setAvatar(SystemUser.DEFAULT_AVATAR);
systemUser.setDescription("注册用户");
userMapper.insert(systemUser);
UserRole userRole = new UserRole();
userRole.setUserId(systemUser.getUserId());
// 注册用户角色 ID
userRole.setRoleId(FebsConstant.REGISTER_ROLE_ID);
userRoleMapper.insert(userRole);
return systemUser;
}
/**
* 注册用户
*/
@Transactional(rollbackFor = Exception.class)
public SystemUser registUser(SystemUser systemUser) {
systemUser.setStatus(SystemUser.STATUS_VALID);
userMapper.insert(systemUser);
UserRole userRole = new UserRole();
userRole.setUserId(systemUser.getUserId());
if (systemUser.getRoleId() != null) {
// 注册用户角色 ID
userRole.setRoleId(Long.valueOf(systemUser.getRoleId()));
userRoleMapper.insert(userRole);
} else if (StrUtil.isNotBlank(systemUser.getRoleName())) {
Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleName, systemUser.getRoleName()));
userRole.setRoleId(role.getRoleId());
userRoleMapper.insert(userRole);
}
return systemUser;
}
/**
* 添加角色
*/
public void addRole(Long userId, Long roleId) {
UserRole userRole = new UserRole();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRoleMapper.insert(userRole);
}
/**
* 查询主角色code字符串
*
* @param mainDeptId 主部门id
* @return java.lang.String
* @author ZYJ
* @date 2022/1/14 10:36
*/
public String findMainRole(Long mainDeptId) {
// 查询主角色code
List<String> rolePerms = userMapper.findMainRole(mainDeptId);
return rolePerms.stream().filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining(StringConstant.COMMA));
}
}

View File

@ -0,0 +1,7 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.EduUserApp;
public interface EduUserAppMapper extends BaseMapper<EduUserApp> {
}

View File

@ -0,0 +1,8 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.EduUserLogo;
public interface EduUserLogoMapper extends BaseMapper<EduUserLogo> {
}

View File

@ -0,0 +1,20 @@
package com.yida.data.auth.mapper;
import com.yida.data.common.core.entity.system.Menu;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* @author MrBird
*/
public interface MenuMapper extends BaseMapper<Menu> {
/**
* 获取用户权限集
*
* @param username 用户名
* @return 权限集合
*/
List<String> findUserPermissions(String username);
}

View File

@ -0,0 +1,11 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.auth.OauthClientDetails;
/**
* @author Yuuki
*/
public interface OauthClientDetailsMapper extends BaseMapper<OauthClientDetails> {
}

View File

@ -0,0 +1,8 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.Role;
public interface RoleMapper extends BaseMapper<Role> {
}

View File

@ -0,0 +1,12 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.UserConnection;
/**
* @author MrBird
*/
public interface UserConnectionMapper extends BaseMapper<UserConnection> {
}

View File

@ -0,0 +1,51 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.entity.system.UserDataPermission;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author MrBird
*/
public interface UserMapper extends BaseMapper<SystemUser> {
/**
* 获取用户
*
* @param username 用户名
* @return 用户
*/
SystemUser findByName(String username);
/**
* 获取用户数据权限
*
* @param userId 用户id
* @return 数据权限
*/
List<UserDataPermission> findUserDataPermissions(Long userId);
/**
* 查询用户
*
* @param deptId 部门
* @param perms 角色perms
* @return
*/
List<SystemUser> listUserByPerms(@Param("deptId") Long deptId,
@Param("perms") String perms);
/**
* 查询主角色code字符串
*
* @param mainDeptId 主部门id
* @return java.util.List<java.lang.String>
* @author ZYJ
* @date 2022/1/14 13:24
*/
List<String> findMainRole(@Param("mainDeptId") Long mainDeptId);
}

View File

@ -0,0 +1,26 @@
package com.yida.data.auth.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yida.data.common.core.entity.system.Menu;
import com.yida.data.common.core.entity.system.SystemUserMenu;
import java.util.List;
/**
* 用户权限dao曾
*
* @author ZYJ
* @date 2021/11/8
*/
public interface UserMenuMapper extends BaseMapper<SystemUserMenu> {
/**
* 通过用户名查询用户权限串
*
* @param username 用户名
* @return java.util.List<com.yida.data.common.core.entity.system.Menu>
* @author ZYJ
* @date 2021/11/8 15:54
*/
List<SystemUserMenu> findUserPermissions(String username);
}

View File

@ -0,0 +1,11 @@
package com.yida.data.auth.mapper;
import com.yida.data.common.core.entity.system.UserRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author MrBird
*/
public interface UserRoleMapper extends BaseMapper<UserRole> {
}

View File

@ -0,0 +1,35 @@
package com.yida.data.auth.properties;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import lombok.Data;
/**
* @author MrBird
*/
@Data
@SpringBootConfiguration
@PropertySource(value = {"classpath:febs-auth.properties"})
@ConfigurationProperties(prefix = "febs.auth")
public class FebsAuthProperties {
/**
* 验证码配置
*/
private FebsValidateCodeProperties code = new FebsValidateCodeProperties();
/**
* JWT加签密钥
*/
private String jwtAccessKey;
/**
* 是否使用 JWT令牌
*/
private Boolean enableJwt;
/**
* 社交登录所使用的 Client
*/
private String socialLoginClientId;
}

View File

@ -0,0 +1,39 @@
package com.yida.data.auth.properties;
import com.yida.data.common.core.entity.constant.ImageTypeConstant;
import lombok.Data;
/**
* @author MrBird
*/
@Data
public class FebsValidateCodeProperties {
/**
* 验证码有效时间单位秒
*/
private Long time = 120L;
/**
* 验证码类型可选值 png和 gif
*/
private String type = ImageTypeConstant.PNG;
/**
* 图片宽度px
*/
private Integer width = 130;
/**
* 图片高度px
*/
private Integer height = 48;
/**
* 验证码位数
*/
private Integer length = 4;
/**
* 验证码值的类型
* 1. 数字加字母
* 2. 纯数字
* 3. 纯字母
*/
private Integer charType = 2;
}

View File

@ -0,0 +1,53 @@
package com.yida.data.auth.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yida.data.common.core.entity.QueryRequest;
import com.yida.data.common.core.entity.auth.OauthClientDetails;
import com.yida.data.common.core.exception.FebsException;
/**
* @author Yuuki
*/
public interface OauthClientDetailsService extends IService<OauthClientDetails> {
/**
* 查询分页
*
* @param request QueryRequest
* @param oauthClientDetails oauthClientDetails
* @return IPage<OauthClientDetails>
*/
IPage<OauthClientDetails> findOauthClientDetails(QueryRequest request, OauthClientDetails oauthClientDetails);
/**
* 根据主键查询
*
* @param clientId clientId
* @return OauthClientDetails
*/
OauthClientDetails findById(String clientId);
/**
* 新增
*
* @param oauthClientDetails oauthClientDetails
* @throws FebsException FebsException
*/
void createOauthClientDetails(OauthClientDetails oauthClientDetails) throws FebsException;
/**
* 修改
*
* @param oauthClientDetails oauthClientDetails
*/
void updateOauthClientDetails(OauthClientDetails oauthClientDetails);
/**
* 删除
*
* @param clientIds clientIds
*/
void deleteOauthClientDetails(String clientIds);
}

View File

@ -0,0 +1,14 @@
package com.yida.data.auth.service;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
public interface SecurityService {
/**
* 得到学校管理员账号的token
*
* @param schoolId
* @return
*/
OAuth2AccessToken getSchoolToken(Long schoolId);
}

View File

@ -0,0 +1,130 @@
package com.yida.data.auth.service;
import com.yida.data.auth.entity.BindUser;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.system.UserConnection;
import com.yida.data.common.core.exception.FebsException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import java.util.List;
import java.util.Map;
/**
* @author MrBird
*/
public interface SocialLoginService {
/**
* 解析第三方登录请求
*
* @param oauthType 第三方平台类型
* @return AuthRequest
* @throws FebsException 异常
*/
AuthRequest renderAuth(String oauthType) throws FebsException;
/**
* 处理第三方登录绑定页面
*
* @param oauthType 第三方平台类型
* @param callback 回调
* @return FebsResponse
* @throws FebsException 异常
*/
FebsResponse resolveBind(String oauthType, AuthCallback callback) throws FebsException;
/**
* 处理第三方登录登录页面
*
* @param oauthType 第三方平台类型
* @param callback 回调
* @return FebsResponse
* @throws FebsException 异常
*/
FebsResponse resolveLogin(String oauthType, AuthCallback callback) throws FebsException;
/**
* 绑定并登录
*
* @param bindUser 绑定用户
* @param authUser 第三方平台对象
* @return OAuth2AccessToken 令牌对象
* @throws FebsException 异常
*/
OAuth2AccessToken bindLogin(BindUser bindUser, AuthUser authUser) throws FebsException;
/**
* 注册并登录
*
* @param registUser 注册用户
* @param authUser 第三方平台对象
* @return OAuth2AccessToken 令牌对象
* @throws FebsException 异常
*/
OAuth2AccessToken signLogin(BindUser registUser, AuthUser authUser) throws FebsException;
/**
* 绑定
*
* @param bindUser 绑定对象
* @param authUser 第三方平台对象
* @throws FebsException 异常
*/
void bind(BindUser bindUser, AuthUser authUser) throws FebsException;
/**
* 解绑
*
* @param bindUser 绑定对象
* @param oauthType 第三方平台对象
* @throws FebsException 异常
*/
void unbind(BindUser bindUser, String oauthType) throws FebsException;
/**
* 根据用户名获取绑定关系
*
* @param username 用户名
* @return 绑定关系集合
*/
List<UserConnection> findUserConnections(String username);
/**
* 企业微信用户登录/注册登录
*/
Map<String, Object> qywxLogin(String code, String state, String corpId, Integer type);
/**
* app用户登录
*/
Map<String, Object> appLogin(String areaId, Long schoolId, String mobile, String userId, Integer type);
Map<String, Object> wxpublicLogin(String code, String appId, Integer type, Long schoolId, String mobile);
Map<String, Object> h5Login(Long schoolId, String mobile, Integer type);
/**
* 检查openId状态
*
* @param code 微信公众号授权code
* @param deptId 学校id
* @return java.util.Map<java.lang.String, java.lang.Object>
* @author ZYJ
* @date 2023/6/2 10:31
*/
Map<String, Object> checkOpenId(String code, Long deptId);
/**
* 迎新功能微信公众号登录
*
* @param openId 微信openId
* @param deptId 学校id
* @return java.util.Map<java.lang.String, java.lang.Object>
* @author ZYJ
* @date 2023/5/18 11:09
*/
Map<String, Object> wxPublicLogin(String openId, Long deptId);
}

View File

@ -0,0 +1,46 @@
package com.yida.data.auth.service;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import com.yida.data.common.core.entity.system.UserConnection;
/**
* @author MrBird
*/
public interface UserConnectionService extends IService<UserConnection> {
/**
* 根据条件查询关联关系
*
* @param providerName 平台名称
* @param providerUserId 平台用户ID
* @return 关联关系
*/
UserConnection selectByCondition(String providerName, String providerUserId);
/**
* 根据条件查询关联关系
*
* @param username 用户名
* @return 关联关系
*/
List<UserConnection> selectByCondition(String username);
/**
* 新增
*
* @param userConnection userConnection
*/
void createUserConnection(UserConnection userConnection);
/**
* 删除
*
* @param username username 用户名
* @param providerName providerName 平台名称
*/
void deleteByCondition(String username, String providerName);
}

View File

@ -0,0 +1,32 @@
package com.yida.data.auth.service;
import com.yida.data.common.core.exception.ValidateCodeException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author MrBird
*/
public interface ValidateCodeService {
/**
* 生成验证码
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
* @throws ValidateCodeException 验证码异常
*/
void create(HttpServletRequest request, HttpServletResponse response) throws IOException, ValidateCodeException;
/**
* 校验验证码
*
* @param key 前端上送 key
* @param value 前端上送待校验值
* @throws ValidateCodeException 验证码异常
*/
void check(String key, String value) throws ValidateCodeException;
}

View File

@ -0,0 +1,95 @@
package com.yida.data.auth.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.yida.data.auth.manager.UserManager;
import cc.mrbird.febs.common.redis.service.RedisService;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.yida.data.common.core.entity.FebsAuthUser;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.constant.ParamsConstant;
import com.yida.data.common.core.entity.constant.SocialConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.utils.FebsUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author MrBird
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class FebsUserDetailServiceImpl implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
private final UserManager userManager;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
HttpServletRequest httpServletRequest = FebsUtil.getHttpServletRequest();
SystemUser systemUser = userManager.findByName(username);
if (systemUser != null) {
List<String> permissions = userManager.findUserPermissions(systemUser.getUsername());
boolean notLocked = false;
if (StringUtils.equals(SystemUser.STATUS_VALID, systemUser.getStatus())) {
notLocked = true;
}
String password = systemUser.getPassword();
String loginType = (String) httpServletRequest.getAttribute(ParamsConstant.LOGIN_TYPE);
if (StringUtils.equals(loginType, SocialConstant.SOCIAL_LOGIN)) {
password = passwordEncoder.encode(SocialConstant.getSocialLoginPassword());
}
List<GrantedAuthority> grantedAuthorities = AuthorityUtils.NO_AUTHORITIES;
// 设置角色权限
if (StringUtils.isNotBlank(systemUser.getRolePerms())) {
List<String> collect = Arrays.stream(systemUser.getRolePerms().split(StringConstant.COMMA))
.map(s -> FebsConstant.SECURITY_ROLE_PREFIX + s)
.distinct()
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(collect)) {
grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList(String.join(StringConstant.COMMA, collect));
}
}
// 设置菜单权限
if (CollUtil.isNotEmpty(permissions)) {
grantedAuthorities.addAll(AuthorityUtils.createAuthorityList(permissions.toArray(new String[0])));
}
// 查询主角色信息
if (Objects.nonNull(systemUser.getMainDeptId())) {
String role = this.userManager.findMainRole(systemUser.getMainDeptId());
systemUser.setMainRolePerms(role);
}
//查询登录所属部门学校对应的
log.info("登陆用户信息sysUser: {}", systemUser);
log.info("登陆权限数据permission: {}", grantedAuthorities);
log.info("登陆主角色数据mainRole: {}", systemUser.getMainRolePerms());
FebsAuthUser authUser = new FebsAuthUser(systemUser.getUsername(), password, true, true, true, notLocked,
grantedAuthorities);
BeanUtils.copyProperties(systemUser, authUser);
return authUser;
} else {
throw new UsernameNotFoundException("");
}
}
}

View File

@ -0,0 +1,111 @@
package com.yida.data.auth.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.yida.data.auth.mapper.OauthClientDetailsMapper;
import com.yida.data.auth.service.OauthClientDetailsService;
import com.yida.data.common.core.entity.QueryRequest;
import com.yida.data.common.core.entity.auth.OauthClientDetails;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.exception.FebsException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author Yuuki
*/
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class OauthClientDetailsServiceImpl extends ServiceImpl<OauthClientDetailsMapper, OauthClientDetails> implements OauthClientDetailsService {
private final PasswordEncoder passwordEncoder;
private final RedisClientDetailsService redisClientDetailsService;
@Override
public IPage<OauthClientDetails> findOauthClientDetails(QueryRequest request, OauthClientDetails oauthClientDetails) {
LambdaQueryWrapper<OauthClientDetails> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(oauthClientDetails.getClientId())) {
queryWrapper.eq(OauthClientDetails::getClientId, oauthClientDetails.getClientId());
}
Page<OauthClientDetails> page = new Page<>(request.getPageNum(), request.getPageSize());
IPage<OauthClientDetails> result = this.page(page, queryWrapper);
List<OauthClientDetails> records = new ArrayList<>();
result.getRecords().forEach(o -> {
o.setOriginSecret(null);
o.setClientSecret(null);
records.add(o);
});
result.setRecords(records);
return result;
}
@Override
public OauthClientDetails findById(String clientId) {
return this.baseMapper.selectById(clientId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void createOauthClientDetails(OauthClientDetails oauthClientDetails) throws FebsException {
OauthClientDetails byId = this.findById(oauthClientDetails.getClientId());
if (byId != null) {
throw new FebsException("该Client已存在");
}
oauthClientDetails.setOriginSecret(oauthClientDetails.getClientSecret());
oauthClientDetails.setClientSecret(passwordEncoder.encode(oauthClientDetails.getClientSecret()));
boolean saved = this.save(oauthClientDetails);
if (saved) {
log.info("缓存Client -> {}", oauthClientDetails);
this.redisClientDetailsService.loadClientByClientId(oauthClientDetails.getClientId());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOauthClientDetails(OauthClientDetails oauthClientDetails) {
String clientId = oauthClientDetails.getClientId();
LambdaQueryWrapper<OauthClientDetails> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(OauthClientDetails::getClientId, oauthClientDetails.getClientId());
oauthClientDetails.setClientId(null);
oauthClientDetails.setClientSecret(null);
boolean updated = this.update(oauthClientDetails, queryWrapper);
if (updated) {
log.info("更新Client -> {}", oauthClientDetails);
this.redisClientDetailsService.removeRedisCache(clientId);
this.redisClientDetailsService.loadClientByClientId(clientId);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteOauthClientDetails(String clientIds) {
Object[] clientIdArray = StringUtils.splitByWholeSeparatorPreserveAllTokens(clientIds, StringConstant.COMMA);
LambdaQueryWrapper<OauthClientDetails> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(OauthClientDetails::getClientId, clientIdArray);
boolean removed = this.remove(queryWrapper);
if (removed) {
log.info("删除ClientId为({})的Client", clientIds);
Arrays.stream(clientIdArray).forEach(c -> this.redisClientDetailsService.removeRedisCache(String.valueOf(c)));
}
}
}

View File

@ -0,0 +1,71 @@
package com.yida.data.auth.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.nio.charset.StandardCharsets;
/**
* 授权码保存到Redis以确保认证服务器集群的一致性
*
* @author MrBird
*/
@Slf4j
@Service
public class RedisAuthenticationCodeService extends RandomValueAuthorizationCodeServices {
private static final String AUTH_CODE_KEY = "auth_code";
private final RedisConnectionFactory connectionFactory;
public RedisAuthenticationCodeService(RedisConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "RedisConnectionFactory required");
this.connectionFactory = connectionFactory;
}
@Override
protected OAuth2Authentication remove(String code) {
RedisConnection conn = getConnection();
try {
byte[] bytes = conn.hGet(AUTH_CODE_KEY.getBytes(StandardCharsets.UTF_8), code.getBytes(StandardCharsets.UTF_8));
if (bytes == null || ArrayUtils.isEmpty(bytes)) {
return null;
}
OAuth2Authentication authentication = SerializationUtils.deserialize(bytes);
if (null != authentication) {
conn.hDel(AUTH_CODE_KEY.getBytes(StandardCharsets.UTF_8), code.getBytes(StandardCharsets.UTF_8));
}
return authentication;
} catch (Exception e) {
return null;
} finally {
conn.close();
}
}
@Override
protected void store(String code, OAuth2Authentication authentication) {
RedisConnection conn = getConnection();
try {
conn.hSet(AUTH_CODE_KEY.getBytes(StandardCharsets.UTF_8), code.getBytes(StandardCharsets.UTF_8),
SerializationUtils.serialize(authentication));
log.info("保存authentication code: {}至redis", code);
} catch (Exception e) {
log.error("保存authentication code至redis失败", e);
} finally {
conn.close();
}
}
private RedisConnection getConnection() {
return connectionFactory.getConnection();
}
}

View File

@ -0,0 +1,101 @@
package com.yida.data.auth.service.impl;
import cc.mrbird.febs.common.redis.service.RedisService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Yuuki
*/
@Slf4j
@Service
public class RedisClientDetailsService extends JdbcClientDetailsService {
/**
* 缓存 client的 redis key这里是 hash结构存储
*/
private static final String CACHE_CLIENT_KEY = "client_details";
private final RedisService redisService;
public RedisClientDetailsService(DataSource dataSource, RedisService redisService) {
super(dataSource);
this.redisService = redisService;
}
@Override
public ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {
ClientDetails clientDetails = null;
String value = (String) redisService.hget(CACHE_CLIENT_KEY, clientId);
if (StringUtils.isBlank(value)) {
clientDetails = cacheAndGetClient(clientId);
} else {
clientDetails = JSONObject.parseObject(value, BaseClientDetails.class);
}
return clientDetails;
}
/**
* 缓存 client并返回 client
*
* @param clientId clientId
*/
public ClientDetails cacheAndGetClient(String clientId) {
ClientDetails clientDetails = null;
clientDetails = super.loadClientByClientId(clientId);
if (clientDetails != null) {
BaseClientDetails baseClientDetails = (BaseClientDetails) clientDetails;
Set<String> autoApproveScopes = baseClientDetails.getAutoApproveScopes();
if (CollectionUtils.isNotEmpty(autoApproveScopes)) {
baseClientDetails.setAutoApproveScopes(
autoApproveScopes.stream().map(this::convert).collect(Collectors.toSet())
);
}
redisService.hset(CACHE_CLIENT_KEY, clientId, JSONObject.toJSONString(baseClientDetails));
}
return clientDetails;
}
/**
* 删除 redis缓存
*
* @param clientId clientId
*/
public void removeRedisCache(String clientId) {
redisService.hdel(CACHE_CLIENT_KEY, clientId);
}
/**
* oauth_client_details全表刷入 redis
*/
public void loadAllClientToCache() {
if (redisService.hasKey(CACHE_CLIENT_KEY)) {
return;
}
log.info("将oauth_client_details全表刷入redis");
List<ClientDetails> list = super.listClientDetails();
if (CollectionUtils.isEmpty(list)) {
log.error("oauth_client_details表数据为空请检查");
return;
}
list.forEach(client -> redisService.hset(CACHE_CLIENT_KEY, client.getClientId(), JSONObject.toJSONString(client)));
}
private String convert(String value) {
final String logicTrue = "1";
return logicTrue.equals(value) ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
}
}

View File

@ -0,0 +1,32 @@
package com.yida.data.auth.service.impl;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.utils.Asserts;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Service;
import java.util.List;
import com.yida.data.auth.mapper.UserMapper;
import com.yida.data.auth.service.SecurityService;
import com.yida.data.auth.util.SecurityUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class SecurityServiceImpl implements SecurityService {
private final UserMapper userMapper;
private final SecurityUtil securityUtil;
@Override
public OAuth2AccessToken getSchoolToken(Long schoolId) {
List<SystemUser> userList = userMapper.listUserByPerms(schoolId, RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue());
Asserts.isTrue(CollUtil.isNotEmpty(userList), "该学校无学校负责人,请创建后重试");
SystemUser schoolUser = userList.get(0);
return securityUtil.getOauth2AccessToken(schoolUser);
}
}

View File

@ -0,0 +1,622 @@
package com.yida.data.auth.service.impl;
import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xkcoding.justauth.AuthRequestFactory;
import com.yida.data.auth.entity.BindUser;
import com.yida.data.auth.manager.UserManager;
import com.yida.data.auth.mapper.RoleMapper;
import com.yida.data.auth.properties.FebsAuthProperties;
import com.yida.data.auth.service.SocialLoginService;
import com.yida.data.auth.service.UserConnectionService;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.constant.*;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideRosterRelation;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideStep;
import com.yida.data.common.core.entity.system.*;
import com.yida.data.common.core.entity.user.EduStaff;
import com.yida.data.common.core.enums.RoleName;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.WxPublicUtil;
import com.yida.data.common.core.utils.WxUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.school.feign.smart.RemoteSmartWelcomeService;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.system.feign.RemoteRoleService;
import com.yida.data.system.feign.RemoteUserService;
import com.yida.data.user.feign.RemoteStaffService;
import com.yida.data.user.feign.RemoteStudentApplyService;
import com.yida.data.user.feign.RemoteStudentService;
import com.yida.data.user.feign.RemoteTeacherService;
import com.yida.data.user.vo.ParentInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author MrBird
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SocialLoginServiceImpl implements SocialLoginService {
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
private static final String NOT_BIND = "not_bind";
private static final String SOCIAL_LOGIN_SUCCESS = "social_login_success";
private final UserManager userManager;
private final RoleMapper roleMapper;
private final AuthRequestFactory factory;
private final FebsAuthProperties properties;
private final PasswordEncoder passwordEncoder;
private final UserConnectionService userConnectionService;
private final ResourceOwnerPasswordTokenGranter granter;
private final RedisClientDetailsService redisClientDetailsService;
private final RemoteStaffService remoteStaffService;
private final RemoteStudentService remoteStudentService;
private final RemoteTeacherService remoteTeacherService;
private final RemoteSmartWelcomeService remoteSmartWelcomeService;
private final WxUtil wxUtil;
private final WxPublicUtil wxPublicUtil;
private final RedisService redisService;
private final CommonService commonService;
@Override
public AuthRequest renderAuth(String oauthType) throws FebsException {
return factory.get(getAuthSource(oauthType));
}
@Override
public FebsResponse resolveBind(String oauthType, AuthCallback callback) throws FebsException {
FebsResponse febsResponse = new FebsResponse();
AuthRequest authRequest = factory.get(getAuthSource(oauthType));
AuthResponse<?> response = authRequest.login(resolveAuthCallback(callback));
if (response.ok()) {
febsResponse.data(response.getData());
} else {
throw new FebsException(String.format("第三方登录失败,%s", response.getMsg()));
}
return febsResponse;
}
@Override
public FebsResponse resolveLogin(String oauthType, AuthCallback callback) throws FebsException {
FebsResponse febsResponse = new FebsResponse();
AuthRequest authRequest = factory.get(getAuthSource(oauthType));
AuthResponse<?> response = authRequest.login(resolveAuthCallback(callback));
if (response.ok()) {
AuthUser authUser = (AuthUser) response.getData();
UserConnection userConnection = userConnectionService
.selectByCondition(authUser.getSource().toString(), authUser.getUuid());
if (userConnection == null) {
febsResponse.message(NOT_BIND).data(authUser);
} else {
SystemUser user = userManager.findByName(userConnection.getUserName());
if (user == null) {
throw new FebsException("系统中未找到与第三方账号对应的账户");
}
OAuth2AccessToken oAuth2AccessToken = getOauth2AccessToken(user);
febsResponse.message(SOCIAL_LOGIN_SUCCESS).data(oAuth2AccessToken);
febsResponse.put(USERNAME, user.getUsername());
}
} else {
throw new FebsException(String.format("第三方登录失败,%s", response.getMsg()));
}
return febsResponse;
}
@Override
public OAuth2AccessToken bindLogin(BindUser bindUser, AuthUser authUser) throws FebsException {
SystemUser systemUser = userManager.findByName(bindUser.getBindUsername());
if (systemUser == null || !passwordEncoder.matches(bindUser.getBindPassword(), systemUser.getPassword())) {
throw new FebsException("绑定系统账号失败,用户名或密码错误!");
}
this.createConnection(systemUser, authUser);
return this.getOauth2AccessToken(systemUser);
}
@Override
public OAuth2AccessToken signLogin(BindUser registUser, AuthUser authUser) throws FebsException {
SystemUser user = this.userManager.findByName(registUser.getBindUsername());
if (user != null) {
throw new FebsException("该用户名已存在!");
}
String encryptPassword = passwordEncoder.encode(registUser.getBindPassword());
SystemUser systemUser = this.userManager.registUser(registUser.getBindUsername(), encryptPassword);
this.createConnection(systemUser, authUser);
return this.getOauth2AccessToken(systemUser);
}
@Override
public void bind(BindUser bindUser, AuthUser authUser) throws FebsException {
String username = bindUser.getBindUsername();
if (isCurrentUser(username)) {
UserConnection userConnection = userConnectionService
.selectByCondition(authUser.getSource().toString(), authUser.getUuid());
if (userConnection != null) {
throw new FebsException("绑定失败,该第三方账号已绑定" + userConnection.getUserName() + "系统账户");
}
SystemUser systemUser = new SystemUser();
systemUser.setUsername(username);
this.createConnection(systemUser, authUser);
} else {
throw new FebsException("绑定失败,您无权绑定别人的账号");
}
}
@Override
public void unbind(BindUser bindUser, String oauthType) throws FebsException {
String username = bindUser.getBindUsername();
if (isCurrentUser(username)) {
this.userConnectionService.deleteByCondition(username, oauthType);
} else {
throw new FebsException("解绑失败,您无权解绑别人的账号");
}
}
@Override
public List<UserConnection> findUserConnections(String username) {
return this.userConnectionService.selectByCondition(username);
}
@Override
public Map<String, Object> qywxLogin(String code, String state, String corpId, Integer type) {
log.info("code:{},state:{},corpid:{}", code, state, corpId);
Dept school = commonService.getSchoolByCorpId(corpId);
// 获取secret
EduApp eduApp = commonService.getAppByCodeAndSchool(state, corpId, null);
log.info("corpId:{},app:{}", corpId, eduApp != null ? eduApp.toString() : "null");
if (eduApp == null || StrUtil.isBlank(eduApp.getWxSecret())) {
throw new FebsException("该应用暂未登记");
}
// 获取access token
String accessToken = wxUtil.getAccessToken(corpId, eduApp.getWxSecret());
// 查询用户信息
JSONObject user = wxUtil.getUserInfo(accessToken, code);
log.info("user:[{}]", user);
// 分别为 企业用户 家长
ParentInfoVO parent = null;
EduStaff teacher = null;
// 家长和教师标识
Object userId = user.get("UserId");
Object parentUserid = user.get("parent_userid");
if (type == 0) {
if (userId != null) {
teacher = remoteStaffService
.getStaffByWxOrMobileOrOpenId(userId.toString(), null, null, school.getDeptId())
.getData();
} else if (parentUserid != null) {
// 通过家长信息转化为职工信息
parent = remoteStudentService.getParentWithStudent(null, parentUserid.toString(),
school.getDeptId()).getData();
if (parent != null) {
teacher = remoteStaffService
.getStaffByWxOrMobileOrOpenId(null, parent.getMobile(), null, school.getDeptId())
.getData();
}
}
} else {
if (parentUserid != null) {
parent = remoteStudentService.getParentWithStudent(null, parentUserid.toString(),
school.getDeptId()).getData();
} else if (userId != null) {
// 通过职工信息转化为家长信息
teacher = remoteStaffService
.getStaffByWxOrMobileOrOpenId(userId.toString(), null, null, school.getDeptId())
.getData();
if (teacher != null) {
parent = remoteStudentService.getParentWithStudent(teacher.getMobile(), null,
school.getDeptId()).getData();
}
}
}
if (teacher == null && parent == null) {
throw new FebsException("该用户暂未注册");
}
// 教师用户查询是否绑定手机号家长必定有手机号
if (type == 0 && StrUtil.isBlank(teacher.getMobile())) {
throw new FebsException("请绑定企业微信手机号");
}
redisService.hset(CachePrefixConstant.USER_LOGIN_DEPT, type == 0 ? teacher.getMobile() :
parent.getMobile(), school.getDeptId());
// 查询系统用户
SystemUser systemUser = userManager.findByName(type == 0 ? teacher.getMobile() : parent.getMobile());
// 系统用户不存在 进行注册
if (systemUser == null) {
systemUser = new SystemUser();
systemUser.setNickname(type == 0 ? teacher.getName() : parent.getMobile());
systemUser.setUsername(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
systemUser.setSex(type == 0 ? teacher.getSex() : "2");
systemUser.setAvatar(type == 0 ? teacher.getAvatar() : SystemUser.DEFAULT_AVATAR);
systemUser.setMobile(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setUserOrigin(0);
systemUser.setDeptId(school.getDeptId());
systemUser.setRoleName(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName());
systemUser.setUserType(type == 0 ? 1 : 0);
// systemUser = remoteUserService.addUser(systemUser).getData();
userManager.registUser(systemUser);
} else if (!systemUser.getRoleName().contains(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName())) {
Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery()
.eq(Role::getRoleName, type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName()));
userManager.addRole(systemUser.getUserId(), role.getRoleId());
systemUser.setRoleId(systemUser.getRoleId() + "," + role.getRoleId());
systemUser.setRoleName(systemUser.getRoleName() + "," + role.getRoleName());
}
// 登录返回token和用户信息
Map<String, Object> res = new HashMap<>();
res.put("token", getOauth2AccessToken(systemUser));
systemUser.setPassword(null);
systemUser.setIdentityId(type == 0 ? teacher.getId() : parent.getParentId());
res.put("user", systemUser);
res.put("identity", type == 0 ? teacher : parent);
return res;
}
@Override
public Map<String, Object> appLogin(String areaId, Long schoolId, String mobile, String userId,
Integer type) {
Dept school = commonService.getDept(schoolId);
Asserts.isNotNull(school, "该学校不存在");
// 分别为 企业用户 家长
ParentInfoVO parent = null;
EduStaff teacher = null;
// 家长和教师标识
if (type == 0) {
teacher = remoteStaffService.getStaffByWxOrMobileOrOpenId(null, mobile, null, school.getDeptId()).getData();
} else {
parent = remoteStudentService.getParentWithStudent(mobile, null, school.getDeptId()).getData();
}
if (teacher == null && parent == null) {
throw new FebsException("该用户未注册");
}
redisService.hset(CachePrefixConstant.USER_LOGIN_DEPT, type == 0 ? teacher.getMobile() :
parent.getMobile(), school.getDeptId());
// 查询系统用户
SystemUser systemUser = userManager.findByName(type == 0 ? teacher.getMobile() : parent.getMobile());
// 系统用户不存在 进行注册
if (systemUser == null) {
// Role role = remoteRoleService.getRoleByNameNoPermission(type == 0 ? "教师" : "家长").getData();
systemUser = new SystemUser();
systemUser.setNickname(type == 0 ? teacher.getName() : parent.getMobile());
systemUser.setUsername(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
systemUser.setSex(type == 0 ? teacher.getSex() : "2");
systemUser.setAvatar(type == 0 ? teacher.getAvatar() : SystemUser.DEFAULT_AVATAR);
systemUser.setMobile(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setUserOrigin(0);
systemUser.setDeptId(type == 0 ? teacher.getSchoolId() : schoolId);
systemUser.setRoleName(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName());
systemUser.setUserType(type == 0 ? 1 : 0);
systemUser.setYidaAppUserId(userId);
userManager.registUser(systemUser);
} else if (!systemUser.getRoleName().contains(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName())) {
Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery()
.eq(Role::getRoleName, type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName()));
userManager.addRole(systemUser.getUserId(), role.getRoleId());
systemUser.setRoleId(systemUser.getRoleId() + "," + role.getRoleId());
systemUser.setRoleName(systemUser.getRoleName() + "," + role.getRoleName());
}
// 用户未绑定appid
if (type == 0 && teacher.getYidaAppUserId() == null) {
remoteTeacherService.saveYidaAppUserId(teacher.getId(), userId);
} else if (type == 1 && parent.getParentYidaAppId() == null) {
remoteStudentService.saveYidaAppUserId(parent.getParentId(), userId);
}
// 登录返回token和用户信息
Map<String, Object> res = new HashMap<>();
res.put("token", getOauth2AccessToken(systemUser));
systemUser.setPassword(null);
systemUser.setIdentityId(type == 0 ? teacher.getId() : parent.getParentId());
res.put("user", systemUser);
res.put("identity", type == 0 ? teacher : parent);
return res;
}
// @Override
// public Map<String, Object> wxpublicLogin(String code, String appId, Integer type, Long schoolId) {
// Dept school = null;
// if (StringUtils.isNotBlank(appId)) {
// school = commonService.getSchoolByAppId(appId);
// } else if (Objects.nonNull(schoolId)) {
// school = commonService.getDept(schoolId);
// }
// if (Objects.isNull(school)) {
// throw new FebsException("学校信息错误");
// }
//
// EduDeptWxPublic wxPublic = commonService.getWxPublic(school.getDeptId());
// // 查询用户信息
// String openId = wxPublicUtil.getOpenId(wxPublic.getAppId(), wxPublic.getSecret(), code);
// log.info(openId);
// // 分别为 企业用户 家长
// ParentInfoVO parent = null;
// EduStaff staff = null;
// if (type == 0) {
// staff = remoteStaffService.getStaffByWxOrMobileOrOpenId(null, null, openId, school.getDeptId()).getData();
// } else {
// }
// if (staff == null && parent == null) {
// throw new FebsException("该用户暂未注册");
// }
// // 教师用户查询是否绑定手机号家长必定有手机号
// if (type == 0 && StrUtil.isBlank(staff.getMobile())) {
// throw new FebsException("请绑定手机号");
// }
// redisService.hset(CachePrefixConstant.USER_LOGIN_DEPT, type == 0 ? staff.getMobile() :
// parent.getMobile(), school.getDeptId());
// // 查询系统用户
// SystemUser systemUser = userManager.findByName(type == 0 ? staff.getMobile() : parent.getMobile());
// // 系统用户不存在 进行注册
// if (systemUser == null) {
//// Role role = remoteRoleService.getRoleByNameNoPermission(type == 0 ? "教师" : "家长").getData();
// systemUser = new SystemUser();
// systemUser.setNickname(type == 0 ? staff.getName() : parent.getMobile());
// systemUser.setUsername(type == 0 ? staff.getMobile() : parent.getMobile());
// systemUser.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
// systemUser.setSex(type == 0 ? staff.getSex() : "2");
// systemUser.setAvatar(type == 0 ? staff.getAvatar() : SystemUser.DEFAULT_AVATAR);
// systemUser.setMobile(type == 0 ? staff.getMobile() : parent.getMobile());
// systemUser.setUserOrigin(0);
// systemUser.setDeptId(school.getDeptId());
// systemUser.setRoleName(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName());
// systemUser.setUserType(type == 0 ? 1 : 0);
// userManager.registUser(systemUser);
// } else if (!systemUser.getRoleName().contains(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName())) {
// Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery()
// .eq(Role::getRoleName, type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName()));
// userManager.addRole(systemUser.getUserId(), role.getRoleId());
// systemUser.setRoleId(systemUser.getRoleId() + "," + role.getRoleId());
// systemUser.setRoleName(systemUser.getRoleName() + "," + role.getRoleName());
// }
// // 登录返回token和用户信息
// Map<String, Object> res = new HashMap<>();
// res.put("token", getOauth2AccessToken(systemUser));
// systemUser.setPassword(null);
// systemUser.setIdentityId(type == 0 ? staff.getId() : parent.getParentId());
// res.put("user", systemUser);
// res.put("identity", type == 0 ? staff : parent);
// return res;
// }
@Override
public Map<String, Object> wxpublicLogin(String code, String appId, Integer type, Long schoolId, String mobile) {
Dept school = null;
if (StringUtils.isNotBlank(appId)) {
school = commonService.getSchoolByAppId(appId);
} else if (Objects.nonNull(schoolId)) {
school = commonService.getDept(schoolId);
}
if (Objects.isNull(school)) {
throw new FebsException("学校信息错误");
}
// 查询用户信息
String openId = wxPublicUtil.getOpenId(school.getWxPublicAppId(), school.getWxPublicSecret(), code);
// 分别为 企业用户 家长
ParentInfoVO parent = null;
EduStaff teacher = null;
// 家长和教师标识
if (type == 0) {
teacher = remoteStaffService.getStaffByWxOrMobileOrOpenId(null, mobile, null, school.getDeptId()).getData();
} else {
parent = remoteStudentService.getParentWithStudent(mobile, null, school.getDeptId()).getData();
}
if (teacher == null && parent == null) {
throw new FebsException("该用户暂未注册");
}
redisService.hset(CachePrefixConstant.USER_LOGIN_DEPT, type == 0 ? teacher.getMobile() :
parent.getMobile(), school.getDeptId());
if (type == 0) {
teacher.setWxPublicOpenId(openId);
remoteStaffService.saveWxPublicOpenId(teacher.getId(), openId);
} else if (type == 1) {
remoteStudentService.saveWxPublicOpenId(parent.getParentId(), openId);
}
// 查询系统用户
SystemUser systemUser = userManager.findByName(type == 0 ? teacher.getMobile() : parent.getMobile());
// 系统用户不存在 进行注册
if (systemUser == null) {
systemUser = new SystemUser();
systemUser.setNickname(type == 0 ? teacher.getName() : parent.getMobile());
systemUser.setUsername(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
systemUser.setSex(type == 0 ? teacher.getSex() : "2");
systemUser.setAvatar(type == 0 ? teacher.getAvatar() : SystemUser.DEFAULT_AVATAR);
systemUser.setMobile(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setUserOrigin(0);
systemUser.setDeptId(school.getDeptId());
systemUser.setRoleName(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName());
systemUser.setUserType(type == 0 ? 1 : 0);
userManager.registUser(systemUser);
} else if (!systemUser.getRoleName().contains(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName())) {
Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery()
.eq(Role::getRoleName, type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName()));
userManager.addRole(systemUser.getUserId(), role.getRoleId());
systemUser.setRoleId(systemUser.getRoleId() + "," + role.getRoleId());
systemUser.setRoleName(systemUser.getRoleName() + "," + role.getRoleName());
}
// 登录返回token和用户信息
Map<String, Object> res = new HashMap<>();
res.put("token", getOauth2AccessToken(systemUser));
systemUser.setPassword(null);
systemUser.setIdentityId(type == 0 ? teacher.getId() : parent.getParentId());
res.put("user", systemUser);
res.put("identity", type == 0 ? teacher : parent);
return res;
}
private void createConnection(SystemUser systemUser, AuthUser authUser) {
UserConnection userConnection = new UserConnection();
userConnection.setUserName(systemUser.getUsername());
userConnection.setProviderName(authUser.getSource().toString());
userConnection.setProviderUserId(authUser.getUuid());
userConnection.setProviderUserName(authUser.getUsername());
userConnection.setImageUrl(authUser.getAvatar());
userConnection.setNickName(authUser.getNickname());
userConnection.setLocation(authUser.getLocation());
this.userConnectionService.createUserConnection(userConnection);
}
private AuthCallback resolveAuthCallback(AuthCallback callback) {
int stateLength = 3;
String state = callback.getState();
String[] strings = StringUtils.splitByWholeSeparatorPreserveAllTokens(state, StringConstant.DOUBLE_COLON);
if (strings.length == stateLength) {
callback.setState(strings[0] + StringConstant.DOUBLE_COLON + strings[1]);
}
return callback;
}
private AuthSource getAuthSource(String type) throws FebsException {
if (StrUtil.isNotBlank(type)) {
return AuthSource.valueOf(type.toUpperCase());
} else {
throw new FebsException(String.format("暂不支持%s第三方登录", type));
}
}
private boolean isCurrentUser(String username) {
String currentUsername = FebsUtil.getCurrentUsername();
return StringUtils.equalsIgnoreCase(username, currentUsername);
}
private OAuth2AccessToken getOauth2AccessToken(SystemUser user) throws FebsException {
final HttpServletRequest httpServletRequest = FebsUtil.getHttpServletRequest();
httpServletRequest.setAttribute(ParamsConstant.LOGIN_TYPE, SocialConstant.SOCIAL_LOGIN);
String socialLoginClientId = properties.getSocialLoginClientId();
ClientDetails clientDetails = null;
try {
clientDetails = redisClientDetailsService.loadClientByClientId(socialLoginClientId);
} catch (Exception e) {
throw new FebsException("获取第三方登录可用的Client失败");
}
if (clientDetails == null) {
throw new FebsException("未找到第三方登录可用的Client");
}
Map<String, String> requestParameters = new HashMap<>(5);
requestParameters.put(ParamsConstant.GRANT_TYPE, GrantTypeConstant.PASSWORD);
requestParameters.put(USERNAME, user.getUsername());
requestParameters.put(PASSWORD, SocialConstant.setSocialLoginPassword());
String grantTypes = String.join(StringConstant.COMMA, clientDetails.getAuthorizedGrantTypes());
TokenRequest tokenRequest = new TokenRequest(requestParameters, clientDetails.getClientId(),
clientDetails.getScope(), grantTypes);
return granter.grant(GrantTypeConstant.PASSWORD, tokenRequest);
}
@Override
public Map<String, Object> h5Login(Long schoolId, String mobile, Integer type) {
Dept school = commonService.getDept(schoolId);
Asserts.isNotNull(school, "该学校不存在");
// 分别为 企业用户 家长
ParentInfoVO parent = null;
EduStaff teacher = null;
// 家长和教师标识
if (type == 0) {
teacher = remoteStaffService.getStaffByWxOrMobileOrOpenId(null, mobile, null, school.getDeptId()).getData();
} else {
parent = remoteStudentService.getParentWithStudent(mobile, null, school.getDeptId()).getData();
}
if (teacher == null && parent == null) {
throw new FebsException("该用户未注册");
}
redisService.hset(CachePrefixConstant.USER_LOGIN_DEPT, type == 0 ? teacher.getMobile() :
parent.getMobile(), school.getDeptId());
// 查询系统用户
SystemUser systemUser = userManager.findByName(type == 0 ? teacher.getMobile() : parent.getMobile());
// 系统用户不存在 进行注册
if (systemUser == null) {
systemUser = new SystemUser();
systemUser.setNickname(type == 0 ? teacher.getName() : parent.getMobile());
systemUser.setUsername(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setPassword(passwordEncoder.encode(SystemUser.DEFAULT_PASSWORD));
systemUser.setSex(type == 0 ? teacher.getSex() : "2");
systemUser.setAvatar(type == 0 ? teacher.getAvatar() : SystemUser.DEFAULT_AVATAR);
systemUser.setMobile(type == 0 ? teacher.getMobile() : parent.getMobile());
systemUser.setUserOrigin(0);
systemUser.setDeptId(type == 0 ? teacher.getSchoolId() : schoolId);
systemUser.setRoleName(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName());
systemUser.setUserType(type == 0 ? 1 : 0);
userManager.registUser(systemUser);
} else if (!systemUser.getRoleName().contains(type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName())) {
Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery()
.eq(Role::getRoleName, type == 0 ? RoleName.STAFF.getName() : RoleName.PARENT.getName()));
userManager.addRole(systemUser.getUserId(), role.getRoleId());
systemUser.setRoleId(systemUser.getRoleId() + "," + role.getRoleId());
systemUser.setRoleName(systemUser.getRoleName() + "," + role.getRoleName());
}
// 登录返回token和用户信息
Map<String, Object> res = new HashMap<>();
res.put("token", getOauth2AccessToken(systemUser));
systemUser.setPassword(null);
systemUser.setIdentityId(type == 0 ? teacher.getId() : parent.getParentId());
res.put("user", systemUser);
res.put("identity", type == 0 ? teacher : parent);
return res;
}
@Override
public Map<String, Object> checkOpenId(String code, Long deptId) {
Dept school = commonService.getDept(deptId);
if (Objects.isNull(school)) {
throw new FebsException("学校信息错误");
}
// 查询用户信息
String openId = wxPublicUtil.getOpenId(school.getWxPublicAppId(), school.getWxPublicSecret(), code);
// 查询openId是否绑定了对应的信息
EduSmartWelcomeGuideRosterRelation relation = remoteSmartWelcomeService.getOpenIdRelation(openId, deptId).getData();
Map<String, Object> map = new HashMap<>();
// true代表已经绑定false代表未绑定
map.put("status", Objects.nonNull(relation));
// 微信openId
map.put("openId", openId);
return map;
}
@Override
public Map<String, Object> wxPublicLogin(String openId, Long deptId) {
// 查询关联关系
EduSmartWelcomeGuideRosterRelation relation = remoteSmartWelcomeService.getOpenIdRelation(openId, deptId).getData();
if (Objects.isNull(relation) || Objects.isNull(relation.getGuideRoster())) {
throw new FebsException("信息错误");
}
// 用户信息
SystemUser systemUser = userManager.findByName(relation.getGuideRoster().getMobile());
// 登录返回token和用户信息
Map<String, Object> res = new HashMap<>();
res.put("token", getOauth2AccessToken(systemUser));
systemUser.setPassword(null);
res.put("user", systemUser);
// // 查询人员步骤信息
// List<EduSmartWelcomeGuideStep> stepList = remoteSmartWelcomeService.listStepInfo(relation.getId(), relation.getGuideId()).getData();
// relation.setStepList(stepList);
res.put("info", relation);
return res;
}
}

View File

@ -0,0 +1,53 @@
package com.yida.data.auth.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import com.yida.data.auth.mapper.UserConnectionMapper;
import com.yida.data.auth.service.UserConnectionService;
import com.yida.data.common.core.entity.system.UserConnection;
/**
* @author MrBird
*/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserConnectionServiceImpl extends ServiceImpl<UserConnectionMapper, UserConnection> implements UserConnectionService {
@Override
public UserConnection selectByCondition(String providerName, String providerUserId) {
LambdaQueryWrapper<UserConnection> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserConnection::getProviderName, providerName)
.eq(UserConnection::getProviderUserId, providerUserId);
return this.baseMapper.selectOne(queryWrapper);
}
@Override
public List<UserConnection> selectByCondition(String username) {
LambdaQueryWrapper<UserConnection> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserConnection::getUserName, username);
return this.baseMapper.selectList(queryWrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void createUserConnection(UserConnection userConnection) {
this.baseMapper.insert(userConnection);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByCondition(String username, String providerName) {
LambdaQueryWrapper<UserConnection> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserConnection::getUserName, username);
queryWrapper.eq(UserConnection::getProviderName, providerName);
this.remove(queryWrapper);
}
}

View File

@ -0,0 +1,85 @@
package com.yida.data.auth.service.impl;
import com.yida.data.auth.properties.FebsAuthProperties;
import com.yida.data.auth.properties.FebsValidateCodeProperties;
import com.yida.data.auth.service.ValidateCodeService;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.constant.ImageTypeConstant;
import com.yida.data.common.core.entity.constant.ParamsConstant;
import com.yida.data.common.core.exception.ValidateCodeException;
import cc.mrbird.febs.common.redis.service.RedisService;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 验证码服务
*
* @author MrBird
*/
@Service
@RequiredArgsConstructor
public class ValidateCodeServiceImpl implements ValidateCodeService {
private final RedisService redisService;
private final FebsAuthProperties properties;
@Override
public void create(HttpServletRequest request, HttpServletResponse response) throws IOException, ValidateCodeException {
String key = request.getParameter(ParamsConstant.VALIDATE_CODE_KEY);
if (StringUtils.isBlank(key)) {
throw new ValidateCodeException("验证码key不能为空");
}
FebsValidateCodeProperties code = properties.getCode();
setHeader(response, code.getType());
Captcha captcha = createCaptcha(code);
redisService.set(FebsConstant.CODE_PREFIX + key, StringUtils.lowerCase(captcha.text()), code.getTime());
captcha.out(response.getOutputStream());
}
@Override
public void check(String key, String value) throws ValidateCodeException {
Object codeInRedis = redisService.get(FebsConstant.CODE_PREFIX + key);
if (StringUtils.isBlank(value)) {
throw new ValidateCodeException("请输入验证码");
}
if (codeInRedis == null) {
throw new ValidateCodeException("验证码已过期");
}
if (!StringUtils.equalsIgnoreCase(value, String.valueOf(codeInRedis))) {
throw new ValidateCodeException("验证码不正确");
}
}
private Captcha createCaptcha(FebsValidateCodeProperties code) {
Captcha captcha = null;
if (StringUtils.equalsIgnoreCase(code.getType(), ImageTypeConstant.GIF)) {
captcha = new GifCaptcha(code.getWidth(), code.getHeight(), code.getLength());
} else {
captcha = new SpecCaptcha(code.getWidth(), code.getHeight(), code.getLength());
}
captcha.setCharType(code.getCharType());
return captcha;
}
private void setHeader(HttpServletResponse response, String type) {
if (StringUtils.equalsIgnoreCase(type, ImageTypeConstant.GIF)) {
response.setContentType(MediaType.IMAGE_GIF_VALUE);
} else {
response.setContentType(MediaType.IMAGE_PNG_VALUE);
}
response.setHeader(HttpHeaders.PRAGMA, "No-cache");
response.setHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
response.setDateHeader(HttpHeaders.EXPIRES, 0L);
}
}

View File

@ -0,0 +1,82 @@
package com.yida.data.auth.translator;
import com.yida.data.common.core.entity.FebsResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
import org.springframework.security.oauth2.common.exceptions.UnsupportedResponseTypeException;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* 异常翻译
*
* @author MrBird
*/
@Slf4j
@Component
@SuppressWarnings("all")
public class FebsWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
@Override
public ResponseEntity<?> translate(Exception e) {
ResponseEntity.BodyBuilder status = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
ResponseEntity.BodyBuilder status1 = ResponseEntity.status(HttpStatus.PAYMENT_REQUIRED);
FebsResponse response = new FebsResponse();
String message = "认证失败";
log.error(message, e);
if (e instanceof UnsupportedGrantTypeException) {
message = "不支持该认证类型";
return status.body(response.message(message));
}
if (e instanceof InvalidTokenException
&& StringUtils.containsIgnoreCase(e.getMessage(), "Invalid refresh token (expired)")) {
message = "刷新令牌已过期,请重新登录";
return status.body(response.message(message));
}
if (e instanceof InvalidScopeException) {
message = "不是有效的scope值";
return status.body(response.message(message));
}
if (e instanceof RedirectMismatchException) {
message = "redirect_uri值不正确";
return status.body(response.message(message));
}
if (e instanceof BadClientCredentialsException) {
message = "client值不合法";
return status.body(response.message(message));
}
if (e instanceof UnsupportedResponseTypeException) {
String code = StringUtils.substringBetween(e.getMessage(), "[", "]");
message = code + "不是合法的response_type值";
return status.body(response.message(message));
}
if (e instanceof InvalidGrantException) {
if (StringUtils.containsIgnoreCase(e.getMessage(), "Invalid refresh token")) {
message = "refresh token无效";
return status1.body(response.message(message));
}
if (StringUtils.containsIgnoreCase(e.getMessage(), "Invalid authorization code")) {
String code = StringUtils.substringAfterLast(e.getMessage(), ": ");
message = "授权码" + code + "不合法";
return status.body(response.message(message));
}
if (StringUtils.containsIgnoreCase(e.getMessage(), "locked")) {
message = "用户已被锁定,请联系管理员";
return status.body(response.message(message));
}
message = "用户名或密码错误";
return status.body(response.message(message));
}
return status.body(response.message(message));
}
}

View File

@ -0,0 +1,59 @@
package com.yida.data.auth.util;
import com.yida.data.common.core.entity.constant.GrantTypeConstant;
import com.yida.data.common.core.entity.constant.ParamsConstant;
import com.yida.data.common.core.entity.constant.SocialConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.yida.data.auth.properties.FebsAuthProperties;
import com.yida.data.auth.service.impl.RedisClientDetailsService;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class SecurityUtil {
private final FebsAuthProperties properties;
private final RedisClientDetailsService redisClientDetailsService;
private final ResourceOwnerPasswordTokenGranter granter;
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
public OAuth2AccessToken getOauth2AccessToken(SystemUser user) throws FebsException {
final HttpServletRequest httpServletRequest = FebsUtil.getHttpServletRequest();
httpServletRequest.setAttribute(ParamsConstant.LOGIN_TYPE, SocialConstant.SOCIAL_LOGIN);
String socialLoginClientId = properties.getSocialLoginClientId();
ClientDetails clientDetails = null;
try {
clientDetails = redisClientDetailsService.loadClientByClientId(socialLoginClientId);
} catch (Exception e) {
throw new FebsException("获取第三方登录可用的Client失败");
}
if (clientDetails == null) {
throw new FebsException("未找到第三方登录可用的Client");
}
Map<String, String> requestParameters = new HashMap<>(5);
requestParameters.put(ParamsConstant.GRANT_TYPE, GrantTypeConstant.PASSWORD);
requestParameters.put(USERNAME, user.getUsername());
requestParameters.put(PASSWORD, SocialConstant.setSocialLoginPassword());
String grantTypes = String.join(StringConstant.COMMA, clientDetails.getAuthorizedGrantTypes());
TokenRequest tokenRequest = new TokenRequest(requestParameters, clientDetails.getClientId(), clientDetails.getScope(), grantTypes);
return granter.grant(GrantTypeConstant.PASSWORD, tokenRequest);
}
}

View File

@ -0,0 +1,3 @@
required=\u4E0D\u80FD\u4E3A\u7A7A
noMoreThan=\u957f\u5ea6\u4e0d\u80fd\u8d85\u8fc7{max}\u4e2a\u5b57\u7b26
invalidNumber=\u4e0d\u662f\u6709\u6548\u7684\u6570\u503c

View File

@ -0,0 +1,8 @@
|------------------------------|
| ____ ____ ___ __ |
| | |_ | |_ | |_) ( (` |
| |_| |_|__ |_|_) _)_) |
| |
| ${spring.application.name} |
| Spring-Boot: ${spring-boot.version} |
|------------------------------|

View File

@ -0,0 +1,34 @@
spring:
profiles:
active: "@env-name@"
application:
name: Edu-Auth
cloud:
nacos:
config:
server-addr: ${nacos.url}
group: DEFAULT_GROUP
prefix: edu-auth
file-extension: yaml
discovery:
server-addr: ${nacos.url}
thymeleaf:
cache: false
logging:
level:
org:
springframework:
boot:
actuate:
endpoint:
EndpointId: error
com:
alibaba:
cloud:
nacos:
client:
NacosPropertySourceBuilder: error
nacos:
client:
naming: warn

View File

@ -0,0 +1,9 @@
febs.auth.enableJwt=false
febs.auth.jwtAccessKey=febs
febs.auth.socialLoginClientId=app
febs.auth.code.time=120
febs.auth.code.type=png
febs.auth.code.width=115
febs.auth.code.height=42
febs.auth.code.length=4
febs.auth.code.charType=2

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yida.data.auth.mapper.MenuMapper">
<select id="findUserPermissions" resultType="java.lang.String">
select distinct m.perms
from t_role r
left join t_user_role ur on (r.role_id = ur.role_id)
left join t_user u on (u.user_id = ur.user_id)
left join t_role_menu rm on (rm.role_id = r.role_id)
left join t_menu m on (m.menu_id = rm.menu_id)
where u.username = #{userName}
and m.perms is not null
and m.perms &lt;&gt; ''
</select>
</mapper>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yida.data.auth.mapper.UserMapper">
<select id="findByName" parameterType="string"
resultType="com.yida.data.common.core.entity.system.SystemUser">
SELECT u.user_id userId,
u.username,
u.nickname,
u.email,
u.mobile,
u.password,
u.status,
u.create_time createTime,
u.ssex sex,
u.dept_id deptId,
u.last_login_time lastLoginTime,
u.modify_time modifyTime,
u.description,
u.avatar,
d.dept_type deptType,
d.school_nature schoolNature,
d.dept_name deptName,
u.agent_id agentId,
GROUP_CONCAT(r.role_id) roleId,
GROUP_CONCAT(r.ROLE_NAME) roleName,
GROUP_CONCAT( r.ROLE_PERMS ) rolePerms,
u.create_id,
u.create_dept_id,
u.main_dept_id,
u.open_id
FROM t_user u
LEFT JOIN t_dept d ON (u.dept_id = d.dept_id)
LEFT JOIN t_user_role ur ON (u.user_id = ur.user_id)
LEFT JOIN t_role r ON r.role_id = ur.role_id
WHERE u.username = #{username}
group by u.username, u.user_id, u.email, u.mobile, u.password, u.status, u.create_time, u.ssex,
u.dept_id
, u.last_login_time, u.modify_time, u.description, u.avatar
</select>
<select id="findUserDataPermissions" parameterType="long"
resultType="com.yida.data.common.core.entity.system.UserDataPermission">
select user_id userId, dept_id deptId
from t_user_data_permission
where user_id = #{userId}
</select>
<select id="listUserByPerms" resultType="com.yida.data.common.core.entity.system.SystemUser">
select a.*
from t_user a left join t_user_role b on a.USER_ID=b.USER_ID
left join t_role c on b.ROLE_ID=c.ROLE_ID
where c.ROLE_PERMS=#{perms}
<if test="deptId != null">
and a.DEPT_ID=#{deptId}
</if>
order by a.USER_ID
</select>
<!-- 查询主角色code字符串 -->
<select id="findMainRole"
resultType="java.lang.String">
SELECT
distinct
r.ROLE_PERMS
FROM
t_user u
INNER JOIN t_user_role ur ON u.USER_ID = ur.USER_ID
INNER JOIN t_role r ON ur.ROLE_ID = r.ROLE_ID
WHERE
u.DEPT_ID = #{mainDeptId}
</select>
</mapper>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yida.data.auth.mapper.UserMenuMapper">
<select id="findUserPermissions" resultType="com.yida.data.common.core.entity.system.SystemUserMenu">
select um.*, m.perms
from t_user_menu um
left join t_user u on (u.user_id = um.user_id)
left join t_menu m on (m.menu_id = um.menu_id)
where u.username = #{userName}
and m.perms is not null
and m.perms <![CDATA[!=]]> ''
</select>
</mapper>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
*{box-sizing:border-box;margin:0;padding:0;font-weight:600;}body{font-family:"Helvetica Neue",Helvetica,Tahoma,Arial,'PingFang SC','Source Han Sans CN','Source Han Sans','Hiragino Sans GB','WenQuanYi Micro Hei',sans-serif;color:white;font-weight:600;}body::-webkit-input-placeholder{font-family:"Helvetica Neue",Helvetica,Tahoma,Arial,'PingFang SC','Source Han Sans CN','Source Han Sans','Hiragino Sans GB','WenQuanYi Micro Hei',sans-serif;color:white;font-weight:600;}body:-moz-placeholder{font-family:"Helvetica Neue",Helvetica,Tahoma,Arial,'PingFang SC','Source Han Sans CN','Source Han Sans','Hiragino Sans GB','WenQuanYi Micro Hei',sans-serif;color:white;opacity:1;font-weight:600;}body::-moz-placeholder{font-family:"Helvetica Neue",Helvetica,Tahoma,Arial,'PingFang SC','Source Han Sans CN','Source Han Sans','Hiragino Sans GB','WenQuanYi Micro Hei',sans-serif;color:white;opacity:1;font-weight:600;}body:-ms-input-placeholder{font-family:"Helvetica Neue",Helvetica,Tahoma,Arial,'PingFang SC','Source Han Sans CN','Source Han Sans','Hiragino Sans GB','WenQuanYi Micro Hei',sans-serif;color:white;font-weight:600;}.wrapper{background-image:linear-gradient(120deg,#e0c3fc 0%,#8ec5fc 100%);position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;}.wrapper.form-success .container h1{-webkit-transform:translateY(85px);transform:translateY(85px);}.container{max-width:600px;margin:0 auto;padding:200px 0;height:400px;text-align:center;}.container h1{font-size:30px;-webkit-transition-duration:1s;transition-duration:1s;-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;font-weight:500;}form{padding:20px 0;position:relative;z-index:2;}form input{-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:0;border:1px solid rgba(255,255,255,0.4);background-color:rgba(255,255,255,0.2);width:300px;border-radius:3px;padding:10px 15px;margin:0 auto 15px auto;display:block;text-align:center;font-size:18px;color:white;-webkit-transition-duration:0.25s;transition-duration:0.25s;font-weight:600;}form input:hover{background-color:rgba(255,255,255,0.4);}form input:focus{background-color:white;width:350px;color:#a6b1e1;}form button{-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:0;background-color:white;border:0;padding:10px 15px;color:#a6b1e1;border-radius:3px;width:300px;cursor:pointer;font-size:18px;-webkit-transition-duration:0.25s;transition-duration:0.25s;}form button:hover{background-color:#f5f7f9;}.bg-bubbles{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;}.bg-bubbles li{position:absolute;list-style:none;display:block;width:40px;height:40px;background-color:rgba(255,255,255,0.15);bottom:-160px;-webkit-animation:square 25s infinite;animation:square 25s infinite;-webkit-transition-timing-function:linear;transition-timing-function:linear;}.bg-bubbles li:nth-child(1){left:10%;}.bg-bubbles li:nth-child(2){left:20%;width:80px;height:80px;-webkit-animation-delay:2s;animation-delay:2s;-webkit-animation-duration:17s;animation-duration:17s;}.bg-bubbles li:nth-child(3){left:25%;-webkit-animation-delay:4s;animation-delay:4s;}.bg-bubbles li:nth-child(4){left:40%;width:60px;height:60px;-webkit-animation-duration:22s;animation-duration:22s;background-color:rgba(255,255,255,0.25);}.bg-bubbles li:nth-child(5){left:70%;}.bg-bubbles li:nth-child(6){left:80%;width:120px;height:120px;-webkit-animation-delay:3s;animation-delay:3s;background-color:rgba(255,255,255,0.2);}.bg-bubbles li:nth-child(7){left:32%;width:160px;height:160px;-webkit-animation-delay:7s;animation-delay:7s;}.bg-bubbles li:nth-child(8){left:55%;width:20px;height:20px;-webkit-animation-delay:15s;animation-delay:15s;-webkit-animation-duration:40s;animation-duration:40s;}.bg-bubbles li:nth-child(9){left:25%;width:10px;height:10px;-webkit-animation-delay:2s;animation-delay:2s;-webkit-animation-duration:40s;animation-duration:40s;background-color:rgba(255,255,255,0.3);}.bg-bubbles li:nth-child(10){left:90%;width:160px;height:160px;-webkit-animation-delay:11s;animation-delay:11s;}@-webkit-keyframes square{0%{-webkit-transform:translateY(0);transform:translateY(0);}100%{-webkit-transform:translateY(-700px) rotate(600deg);transform:translateY(-700px) rotate(600deg);}}@keyframes square{0%{-webkit-transform:translateY(0);transform:translateY(0);}100%{-webkit-transform:translateY(-700px) rotate(600deg);transform:translateY(-700px) rotate(600deg);}}

View File

@ -0,0 +1 @@
$(function(){var a=$("#username"),b=$("#password");$("#login").on("click",function(c){var d,e;return c.preventDefault(),d=a.val().trim(),e=b.val().trim(),""===d?(alert("用户名不能为空"),void 0):""===e?(alert("密码不能为空"),void 0):($.post(ctx+"login",{username:d,password:e},function(a){window.location.href=a.data}).error(function(a){console.error(a),alert(a.responseJSON.message)}),void 0)})});

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="ch" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport">
<meta content="ie=edge" http-equiv="X-UA-Compatible">
<link rel="icon" th:href="@{resource/favicon.ico}" type="image/x-icon"/>
<title>第三方登录失败</title>
</head>
<style>
span{font-size:.9rem;font-weight:bold;color:#42b983}
</style>
<body>
<span>[[${error}]]</span>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="ch" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport">
<meta name="description" content="FEBS Cloud授权码模式登录页面">
<meta name="author" content="MrBird">
<link rel="stylesheet" th:href="@{resource/login.min.css}" media="all">
<script th:src="@{resource/jQuery-2.1.4.min.js}"></script>
<link rel="icon" th:href="@{resource/favicon.ico}" type="image/x-icon"/>
<title>FEBS系统登录</title>
</head>
<body>
<div class="wrapper">
<div class="container"><h1>FEBS 系统登录</h1>
<form class="form"><input type="text" placeholder="用户名" id="username"><input type="password" placeholder="密码"
id="password">
<button type="submit" id="login">登录</button>
</form>
</div>
<ul class="bg-bubbles">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</body>
<script th:inline="javascript">
var ctx = [[@{/}]];
</script>
<script th:src="@{resource/login.min.js}"></script>
</html>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="ch" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport">
<meta content="ie=edge" http-equiv="X-UA-Compatible">
<link rel="icon" th:href="@{resource/favicon.ico}" type="image/x-icon"/>
<title>登录跳转中</title>
</head>
<body>
登录中..
<script th:inline="javascript">
var response = [[${response}]];
var frontUrl = [[${frontUrl}]];
window.onload = function () {
window.opener.postMessage(response, frontUrl);
window.close();
}
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<a
href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wwbbc43a5b210ddb23&redirect_uri=http%3A%2F%2Fzbz.yd-data.com%3A8301%2Fauth%2Ftest&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect">test</a>
</body>
</html>

25
edu-auth/pom.xml Normal file
View File

@ -0,0 +1,25 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>febs-cloud</artifactId>
<groupId>com.yida.data</groupId>
<version>2.2-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.yida.data.auth</groupId>
<artifactId>edu-auth</artifactId>
<packaging>pom</packaging>
<modules>
<module>edu-auth-biz</module>
<module>edu-auth-api</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>febs-common</artifactId>
<groupId>com.yida.data</groupId>
<version>2.2-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>FEBS-Common-Core</name>
<description>FEBS-Common-Core系统核心模块</description>
<packaging>jar</packaging>
<artifactId>febs-common-core</artifactId>
<dependencies>
<!-- 图片压缩-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>${thumbnailator.version}</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>${xml-api.version}</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--redis-->
<dependency>
<groupId>com.yida.data</groupId>
<artifactId>febs-common-redis-starter</artifactId>
<version>2.2-RELEASE</version>
</dependency>
<!-- 鉴权-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<!-- 微服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 监控-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--es-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
<!--excel操作-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!--微信支付-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>${wxpay.apiv3.version}</version>
<scope>compile</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.github.wechatpay-apiv3</groupId>-->
<!-- <artifactId>wechatpay-apache-httpclient</artifactId>-->
<!-- <version>${wxpay.apiv3.version}</version>-->
<!-- <scope>compile</scope>-->
<!-- </dependency>-->
<!-- 二维码依赖 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${qr.code.version}</version>
</dependency>
<!-- 百度api -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>${baidu.api.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
package com.yida.data.common.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author MrBird
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ControllerLog {
String operation() default "";
String exceptionMessage() default "系统内部异常";
}

View File

@ -0,0 +1,20 @@
package com.yida.data.common.core.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* @author MrBird
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Fallback {
@AliasFor(annotation = Component.class)
String value() default "";
}

View File

@ -0,0 +1,18 @@
package com.yida.data.common.core.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* @author MrBird
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Helper {
@AliasFor(annotation = Component.class)
String value() default "";
}

View File

@ -0,0 +1,26 @@
package com.yida.data.common.core.annotation;
import com.yida.data.common.core.validator.MobileValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author MrBird
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MobileValidator.class)
public @interface IsMobile {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,36 @@
package com.yida.data.common.core.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
/**
* @author MrBird
*/
public abstract class BaseAspectSupport {
Method resolveMethod(ProceedingJoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
Class<?> targetClass = point.getTarget().getClass();
Method method = getDeclaredMethod(targetClass, signature.getName(),
signature.getMethod().getParameterTypes());
if (method == null) {
throw new IllegalStateException("无法解析目标方法: " + signature.getMethod().getName());
}
return method;
}
private Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
try {
return clazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
return getDeclaredMethod(superClass, name, parameterTypes);
}
}
return null;
}
}

View File

@ -0,0 +1,61 @@
package com.yida.data.common.core.common;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* app分页请求基类
*
* @author ZYJ
* @date 2021/9/6
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class AppPageRequestBaseDTO<T> implements Serializable {
private static final long serialVersionUID = 1707879624681989241L;
/**
* 当前页码
*/
@ApiModelProperty(value = "当前页码", required = true)
private Integer pageNo;
/**
* 页面大小
*/
@ApiModelProperty(value = "页面大小", required = true)
private Integer pageSize;
/**
* 用户id
*/
@NotNull
@ApiModelProperty(value = "用户id", required = true)
private Long userId;
/**
* 用户名
*/
@ApiModelProperty(value = "用户名")
private String userName;
/**
* 用户昵称
*/
@ApiModelProperty(value = "用户昵称")
private String nickName;
public Page<T> toPage() {
return new Page<>(this.pageNo, this.pageSize);
}
}

View File

@ -0,0 +1,44 @@
package com.yida.data.common.core.common;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* app请求基类
*
* @author ZYJ
* @date 2021/9/6
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class AppRequestBaseDTO implements Serializable {
private static final long serialVersionUID = -1679661038447970238L;
/**
* 用户id
*/
@NotNull
@ApiModelProperty(value = "用户id", required = true)
private Long userId;
/**
* 用户名
*/
@ApiModelProperty(value = "用户名")
private String userName;
/**
* 用户昵称
*/
@ApiModelProperty(value = "用户昵称")
private String nickName;
}

View File

@ -0,0 +1,26 @@
package com.yida.data.common.core.common;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseDTO<T> {
@ApiModelProperty("当前页码默认为1")
private Integer pageNum = 1;
@ApiModelProperty("页面大小默认为10")
private Integer pageSize = 10;
public Page<T> toPage() {
return new Page<>(this.pageNum, this.pageSize);
}
}

View File

@ -0,0 +1,36 @@
package com.yida.data.common.core.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
public enum ModuleName {
AUTH("认证中心"),
APPLY_PARODUCT("应用商品"),
ATTENDANCE("考勤"),
DEVICE("设备"),
LETTER_BOX("校长信箱"),
NOTICE("通知"),
SCHOOL("校园主页"),
STUDENT_EXAM("考试管理"),
USER("用户管理"),
STUDENT("学生管理"),
STAFF("职工管理"),
JOB("任务调度"),
SYSTEM("系统管理"),
DEPT("系统部门"),
USER_DEPT("家校部门"),
INSTRUCTION("系统指南"),
ELECTRONIC_STUDENT_CARD("电子学生证"),
TELEPHONE("亲情电话"),
COURSE("课程表"),
PRODUCT("商品管理"),
TRANSATION("交易管理"),
HEALTH("健康管理");
@Getter
String name;
public String getName() {
return name;
}
}

View File

@ -0,0 +1,130 @@
package com.yida.data.common.core.common;
import lombok.Data;
/**
* @author sweeter
* @date 2019/6/17
* 接口返回对象
*/
@Data
public class ResultBean<T> {
/**
* 状态 200:成功
*/
private int status = ResultStatusType.SUCCESS.getValue();
/**
* 中文消息
*/
private String message = ResultMsgType.SUCCESS.getValue();
/**
* 总条数
*/
private long count;
/**
* 数据对象
*/
private T data;
public ResultBean() {
this.count = 0;
}
public ResultBean(T data) {
this(ResultStatusType.SUCCESS.getValue(), ResultMsgType.SUCCESS.getValue(), data);
}
public ResultBean(int status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
public ResultBean(int status, String message, T data, long count) {
this.status = status;
this.message = message;
this.data = data;
this.count = count;
}
/**
* 失败传入描述信息
**/
public static <T> ResultBean<T> buildError(String message) {
return new ResultBean<>(ResultStatusType.FAIL.getValue(), message, null);
}
/**
* 失败传入描述信息,加错误内容
**/
public static <T> ResultBean<T> buildError(String message, T data) {
return new ResultBean<>(ResultStatusType.FAIL.getValue(), message, data);
}
/**
* 成功传入数据
**/
public static <T> ResultBean<T> buildSuccess(T data) {
return new ResultBean<>(ResultStatusType.SUCCESS.getValue(), ResultMsgType.SUCCESS.getValue(), data);
}
/**
* 失败传入描述信息,状态码
**/
public static <T> ResultBean<T> buildError(String msg, Integer code) {
return new ResultBean<>(code, msg, null);
}
/**
* 成功传入数据,及状态码
**/
public static <T> ResultBean<T> buildSuccess(T data, int code) {
return new ResultBean<>(code, null, data);
}
/**
* 成功不传入数据
**/
public static <T> ResultBean<T> buildSuccess() {
return new ResultBean<>(ResultStatusType.SUCCESS.getValue(), ResultMsgType.SUCCESS.getValue(), null);
}
public static <T> ResultBean<T> buildSuccess(T data, long count) {
return new ResultBean<>(ResultStatusType.SUCCESS.getValue(), ResultMsgType.SUCCESS.getValue(), data, count);
}
public static <T> ResultBean<T> buildSuccess(long count, T data) {
return new ResultBean<>(ResultStatusType.SUCCESS.getValue(), null, data, count);
}
/**
* 成功返回指定消息
*
* @param message 返回的成功消息
* @param data 返回的数据
* @return com.yida.data.common.core.common.ResultBean<T>
* @author ZYJ
* @date 2021/8/23 16:58
*/
public static <T> ResultBean<T> buildSuccess(String message, T data) {
return new ResultBean<>(ResultStatusType.SUCCESS.getValue(), message, data);
}
/**
* 失败传入状态码, 描述信息和失败的提示数据
*
* @param status 返回的状态码
* @param message 返回的描述信息
* @param data 返回的数据
* @return com.yida.data.common.core.common.ResultBean<T>
* @author ZYJ
* @date 2021/8/23 16:59
*/
public static <T> ResultBean<T> buildError(Integer status, String message, T data) {
return new ResultBean<>(status, message, data);
}
}

View File

@ -0,0 +1,64 @@
package com.yida.data.common.core.common;
/**
* @author sweeter
* @date 2019/6/17
* 消息返回类型
*/
public enum ResultMsgType {
/**
* 消息返回类型
*/
SUCCESS("成功", 200),
IMPORT_EXCEL_SUCCESS("导入成功", 200),
FAIL("系统内部异常", 500),
QUERY_FAIL("查询失败", 500),
SAVE_FAIL("保存失败", 500),
DELETE_FAIL("删除失败", 500),
CHECK_FAIL("验证失败", 500),
IMPORT_EXCEL_FAIL("导入失败!", 500),
FILE_TYPE_ERROR("导入文件类型错误", 500),
ID_CARD_EXIST("身份证号码已存在!", 500),
STUDENT_CARD_NUMBER_EXIST("校园学号已存在!", 500),
STUDENT_NUMBER_EXIST("学号已存在!", 500),
STUDENT_NUMBER_NOT_EXIST("学号不存在!", 500),
CAMPUS_NAME_ERROR("学区名称错误", 500),
SECTION_NAME_ERROR("学段名称错误", 500),
GRADE_NAME_ERROR("年级名称错误", 500),
CLASS_NAME_ERROR("班级名称错误", 500),
START_DATE_ERROR("入学时间错误", 500),
SERVER_ERROR("服务器繁忙!请稍后再试", 500),
LOGIN_INFO_ERROR("用户登陆信息异常", 500),
PAY_TYPE_ERROR("暂不支持此支付方式", 500),
ORDER_FAIL("创建订单失败!请稍后再试", 500),
ORDER_NOT_FOUND("未找到订单信息", 500),
ORDER_INVALID("该订单已失效!无法执行该操作", 500),
ORDER_QUERY_FAIL("订单查询失败", 500),
ORDER_CLOSE_FAIL("关闭订单失败", 500),
ORDER_REFUND_FAIL("订单退款失败", 500),
REFUND_QUERY_FAIL("退款查询失败", 500),
ORDER_MONEY_ERROR("订单金额异常", 500),
CARD_STATUS_ERROR("卡状态异常", 500),
;
private final String value;
private final Integer status;
ResultMsgType(String value, Integer status) {
this.value = value;
this.status = status;
}
public String getValue() {
return value;
}
public Integer getStatus() {
return status;
}
}

View File

@ -0,0 +1,24 @@
package com.yida.data.common.core.common;
/**
* @author sweeter
* @date 2019/6/17
*/
public enum ResultStatusType {
/**
* 返回状态 200成功 500失败
*/
SUCCESS(200),
FAIL(500),
IMPORT_FAIL(555);
private final int value;
ResultStatusType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@ -0,0 +1,18 @@
package com.yida.data.common.core.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class AsyncCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String appName = environment.getProperty("spring.application.name");
return !"FEBS-Server-Job".equals(appName);
}
}

View File

@ -0,0 +1,16 @@
package com.yida.data.common.core.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LogCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
Boolean enableLog = Boolean.valueOf(environment.getProperty("febs.sysLog"));
return enableLog;
}
}

View File

@ -0,0 +1,37 @@
package com.yida.data.common.core.configure;
import com.yida.data.common.core.condition.AsyncCondition;
import com.yida.data.common.core.entity.constant.FebsConstant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author MrBird
*/
@Configuration
public class AsyncPollConfigure {
/**
* 注册异步线程池
*/
@Bean(FebsConstant.ASYNC_POOL)
@Conditional(AsyncCondition.class)
public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(30);
executor.setThreadNamePrefix("Febs-Async-Thread");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

View File

@ -0,0 +1,34 @@
package com.yida.data.common.core.converter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class LocalDateConverter implements Converter<LocalDate> {
@Override
public Class<LocalDate> supportJavaTypeKey() {
return LocalDate.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDate convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public CellData<String> convertToExcelData(LocalDate value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
}

View File

@ -0,0 +1,34 @@
package com.yida.data.common.core.converter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeConverter implements Converter<LocalDateTime> {
@Override
public Class<LocalDateTime> supportJavaTypeKey() {
return LocalDateTime.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public CellData<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}

View File

@ -0,0 +1,102 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yida.data.common.core.entity.system.EduUserLogo;
import com.yida.data.common.core.entity.system.enums.DeptTypeEnum;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
/**
* @author MrBird
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CurrentUser implements Serializable {
private static long serialVersionUID = 761748087824726463L;
@JsonIgnore
private String password;
private String username;
private String nickname;
@JsonIgnore
private Set<GrantedAuthority> authorities;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
private Long userId;
private String avatar;
private String email;
private String mobile;
private String sex;
private Long deptId;
/**
* 部门类型 {@link DeptTypeEnum}
*/
private Integer deptType;
private String deptName;
private String roleId;
private String roleName;
/**
* 角色标识
*/
private String rolePerms;
@JsonIgnore
private LocalDateTime lastLoginTime;
private String description;
private String status;
private String deptIds;
private String openId;
private Long identityId;
/**
* 代理商部门id(角色为代理商相关时存在)
*/
private Long agentId;
/**
* 角色类型集合 {@link RoleEnum}
*/
private List<Integer> roleTypeList;
/**
* 创建人id
*/
private Long createId;
/**
* 创建人部门id
*/
private Long createDeptId;
/**
* 主部门id(学校教育局代理商主部门id)
*/
private Long mainDeptId;
/**
* 主角色标识
*/
private String mainRolePerms;
/**
* 学校性质0幼儿园1小学2中学3九年一贯4十二年一贯5高校
*/
private Integer schoolNature;
@JsonIgnore
private EduUserLogo userLogo;
}

View File

@ -0,0 +1,107 @@
package com.yida.data.common.core.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yida.data.common.core.entity.apply.enums.DelFlagType;
import com.yida.data.common.core.enums.EnableStatusEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 部门-学校关联表 Entity
*
* @author ZYJ
* @date 2021-11-23
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_dept_school_relate")
public class DeptSchoolRelate implements Serializable {
private static final long serialVersionUID = -3897472329708532245L;
/**
* 主键id
*/
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 是否删除1删除0未删除默认0
* {@link DelFlagType}
*/
@ApiModelProperty(value = "是否删除1删除0未删除默认0")
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@ApiModelProperty(value = "创建人id")
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 最后修改时间
*/
@ApiModelProperty(value = "最后修改时间")
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 最后修改人id
*/
@ApiModelProperty(value = "最后修改人id")
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
/**
* 部门id
*/
@ApiModelProperty(value = "部门id")
@TableField("dept_id")
private Long deptId;
/**
* 学校id
*/
@ApiModelProperty(value = "学校id")
@TableField("school_id")
private Long schoolId;
/**
* 启用状态. 0:未启用, 1:已启用
* {@link EnableStatusEnum}
*/
@ApiModelProperty(value = "启用状态. 0:未启用, 1:已启用")
@TableField("enable_status")
private Integer enableStatus;
/**
* 创建人部门id
*/
@TableField("create_dept_id")
private Long createDeptId;
}

View File

@ -0,0 +1,36 @@
package com.yida.data.common.core.entity;
import com.yida.data.common.core.entity.system.Dept;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author MrBird
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptTree extends Tree<Dept> {
private Integer orderNum;
private Long wxId;
private Integer type;
private Long parentWxId;
private String corpId;
private String wxCallToken;
private String wxAesKey;
private Long yidaAppId;
private String icon;
private List<Long> relationSchoolList;
}

View File

@ -0,0 +1,60 @@
package com.yida.data.common.core.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.yida.data.common.core.entity.apply.enums.DelFlagType;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("t_dict")
public class Dict implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 数据值
*/
@ApiModelProperty("数据值")
@TableField("value")
private String value;
/**
* 标签名
*/
@ApiModelProperty("标签名")
@TableField("label")
private String label;
/**
* 类型
*/
@ApiModelProperty("类型")
@TableField("type")
private String type;
/**
* 描述
*/
@ApiModelProperty("描述")
@TableField("description")
private String description;
/**
* 排序
*/
@ApiModelProperty("排序")
@TableField("sort")
private Integer sort;
/**
* 父级id
*/
@ApiModelProperty("父级id")
@TableField("parent_id")
private Integer parentId;
/**
* 是否删除1删除0未删除默认0'
*/
@ApiModelProperty("部门类型")
@TableLogic(value = "0", delval = "1")
private Integer delFlag = DelFlagType.NORMAL_TYPE.getValue();
}

View File

@ -0,0 +1,15 @@
package com.yida.data.common.core.entity;
import java.io.Serializable;
/**
* EasyExcel导出基类
*
* @author ZYJ
* @date 2021/8/24
*/
public class EasyExcelExportBaseDTO implements Serializable {
private static final long serialVersionUID = -8454018740909086736L;
}

View File

@ -0,0 +1,68 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yida.data.common.core.enums.RecordTypeEnum;
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 通行记录错误信息
*
* @author ZYJ
* @date 2023/11/1 14:00
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "error_record_msg", shards = 5)
public class ErrorRecordMsg {
@Id
private String id;
/**
* 创建时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 学校id
*/
@Field(type = FieldType.Long)
private Long schoolId;
/**
* 处理的信息. AddAttendanceRecordDTO
*/
@Field(type = FieldType.Text)
private String msg;
/**
* 消息渠道-内部标识
*/
@Field(type = FieldType.Text)
private String topic;
/**
* 消息来源渠道
*/
@Field(type = FieldType.Text)
private String channel;
/**
* 通行记录类型 {@link RecordTypeEnum}
*/
@Field(type = FieldType.Text)
private String recordType;
}

View File

@ -0,0 +1,101 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yida.data.common.core.entity.system.EduUserLogo;
import java.time.LocalDateTime;
import java.util.Collection;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
/**
* @author MrBird
*/
@Data
@SuppressWarnings("all")
@EqualsAndHashCode(callSuper = true)
public class FebsAuthUser extends User {
private static final long serialVersionUID = -6411066541689297219L;
private String nickname;
private Long userId;
private String avatar;
private String email;
private String mobile;
private String sex;
private Long deptId;
private Integer deptType;
private String deptName;
private String roleId;
private String roleName;
/**
* 角色标识
*/
private String rolePerms;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime lastLoginTime;
private String description;
private String status;
private Integer schoolNature;
private String deptIds;
private Long identityId;
private String openId;
/**
* 代理商id(角色为代理商相关时存在)
*/
private Long agentId;
/**
* 创建人id
*/
private Long createId;
/**
* 创建人部门id
*/
private Long createDeptId;
/**
* 主部门id(学校或教育局部门id)
*/
private Long mainDeptId;
/**
* 主角色标识
*/
private String mainRolePerms;
private EduUserLogo userLogo;
public FebsAuthUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
public FebsAuthUser(String username, String password, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
}
}

View File

@ -0,0 +1,35 @@
package com.yida.data.common.core.entity;
import java.util.HashMap;
/**
* @author MrBird
*/
public class FebsResponse extends HashMap<String, Object> {
private static final long serialVersionUID = -8713837118340960775L;
public FebsResponse message(String message) {
this.put("message", message);
return this;
}
public FebsResponse data(Object data) {
this.put("data", data);
return this;
}
@Override
public FebsResponse put(String key, Object value) {
super.put(key, value);
return this;
}
public String getMessage() {
return String.valueOf(get("message"));
}
public Object getData() {
return get("data");
}
}

View File

@ -0,0 +1,93 @@
package com.yida.data.common.core.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 获取小程序URL Link请求类
*
* @author ZYJ
* @date 2022/6/21
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GenerateUrlLink implements Serializable {
private static final long serialVersionUID = 5160809466719710274L;
/**
* 通过 URL Link 进入的小程序页面路径必须是已经发布的小程序存在的页面不可携带 query path 为空时会跳转小程序主页
*/
private String path;
/**
* 通过 URL Link 进入小程序时的query最大1024个字符只支持数字大小写英文以及部分特殊字符!#$&'()*+,/:;=?@-._~%
*/
private String query;
/**
* 要打开的小程序版本正式版为 "release"体验版为"trial"开发版为"develop"仅在微信外打开时生效
*/
private String envVersion;
/**
* 小程序 URL Link 失效类型失效时间0失效间隔天数1
* 必填
*/
private Integer expireType;
/**
* 到期失效的 URL Link 的失效时间 Unix 时间戳生成的到期失效 URL Link 在该时间前有效最长有效期为30天expire_type 0 必填
*/
private Integer expireTime;
/**
* 到期失效的URL Link的失效间隔天数生成的到期失效URL Link在该间隔时间到达前有效最长间隔天数为30天expire_type 1 必填
*/
private Integer expireInterval;
/**
* 云开发静态网站自定义 H5 配置参数可配置中转的云开发 H5 页面不填默认用官方 H5 页面
*/
private CloudBase cloudBase;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CloudBase implements Serializable {
private static final long serialVersionUID = 6571196235936393363L;
/**
* 云开发环境
*/
private String env;
/**
* 静态网站自定义域名不填则使用默认域名
*/
private String domain;
/**
* 云开发静态网站 H5 页面路径不可携带 query
*/
private String path;
/**
* 云开发静态网站 H5 页面 query 参数最大 1024 个字符只支持数字大小写英文以及部分特殊字符`!#$&'()*+,/:;=?@-._~%``
*/
private String query;
/**
* 第三方批量代云开发时必填表示创建该 env appid 小程序/第三方平台
*/
private String resourceAppId;
}
}

View File

@ -0,0 +1,21 @@
package com.yida.data.common.core.entity;
import com.yida.data.common.core.entity.system.Menu;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author MrBird
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class MenuTree extends Tree<Menu> {
private String path;
private String component;
private String perms;
private String icon;
private String type;
private Integer orderNum;
}

View File

@ -0,0 +1,32 @@
package com.yida.data.common.core.entity;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* @author MrBird
*/
@Data
@ToString
public class QueryRequest implements Serializable {
private static final long serialVersionUID = -4869594085374385813L;
/**
* 当前页面数据量
*/
private int pageSize = 10;
/**
* 当前页码
*/
private int pageNum = 1;
/**
* 排序字段
*/
private String field;
/**
* 排序规则asc升序desc降序
*/
private String order;
}

View File

@ -0,0 +1,43 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Data
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "receive_msg", shards = 5)
public class ReceiveMsg {
@Id
private Long id;
/**
* 创建时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 接收的消息
*/
private String msg;
/**
* 消息渠道-内部标识
*/
private String topic;
/**
* 消息来源渠道
*/
private String channel;
}

View File

@ -0,0 +1,37 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* @author MrBird
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Tree<T> {
private String id;
private String label;
private List<Tree<T>> children;
private String parentId;
private boolean hasParent = false;
private boolean hasChildren = false;
/**
* 是否禁用
*/
private boolean disabled = false;
public void initChildren() {
this.children = new ArrayList<>();
}
}

View File

@ -0,0 +1,43 @@
package com.yida.data.common.core.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.entity.user.enums.SectionTypeEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
* 家校部门树实体类
*
* @author ZYJ
* @date 2021-11-12
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserDeptTree extends Tree<EduUserDept> {
private Integer orderNum;
private Long wxId;
private Integer type;
private Long parentWxId;
private String icon;
private Long schoolId;
/**
* 学段类型. 当家校部门类型为3时存在
* {@link SectionTypeEnum}
*/
private String sectionType;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
}

View File

@ -0,0 +1,31 @@
package com.yida.data.common.core.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class WxPublicQr implements Serializable {
private static final long serialVersionUID = 4930203914521367827L;
/**
* 扫描用户微信公众号下openId
*/
private String userOpenId;
/**
* 消息唯一标识
* 代理商部门id
*/
private String flag;
/**
* 学校id公众号为学校绑定时有该数据
*/
private Long schoolId;
/**
* 扫描绑定时的登陆用户id
*/
private Long userId;
}

View File

@ -0,0 +1,111 @@
package com.yida.data.common.core.entity.agent;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 代理商表 Entity
*
* @author ZYJ
* @date 2021-09-26 11:19:45
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("edu_agent")
public class EduAgent implements Serializable {
private static final long serialVersionUID = -1712402383539841679L;
/**
* 主键id
*/
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 是否删除1删除0未删除默认0
*/
@ApiModelProperty(value = "是否删除1删除0未删除默认0")
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@ApiModelProperty(value = "创建人id")
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 最后修改时间
*/
@ApiModelProperty(value = "最后修改时间")
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 最后修改人id
*/
@ApiModelProperty(value = "最后修改人id")
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
/**
* 代理商名称
*/
@ApiModelProperty(value = "代理商名称")
@TableField("agent_name")
private String agentName;
/**
* 区域id
*/
@ApiModelProperty(value = "区域id")
@TableField("area_id")
private Long areaId;
/**
* 负责人名称
*/
@ApiModelProperty(value = "负责人名称")
@TableField("principal_name")
private String principalName;
/**
* 负责人电话
*/
@ApiModelProperty(value = "负责人电话")
@TableField("principal_phone")
private String principalPhone;
/**
* 地址
*/
@ApiModelProperty(value = "地址")
@TableField("address")
private String address;
}

View File

@ -0,0 +1,99 @@
package com.yida.data.common.core.entity.agent;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yida.data.common.core.enums.EnableStatusEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 代理商-学校关联表 Entity
*
* @author ZYJ
* @date 2021-09-26 15:41:06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("edu_agent_school_relate")
public class EduAgentSchoolRelate implements Serializable {
private static final long serialVersionUID = 360901931783594616L;
/**
* 主键id
*/
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 是否删除1删除0未删除默认0
*/
@ApiModelProperty(value = "是否删除1删除0未删除默认0")
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@ApiModelProperty(value = "创建人id")
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 最后修改时间
*/
@ApiModelProperty(value = "最后修改时间")
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 最后修改人id
*/
@ApiModelProperty(value = "最后修改人id")
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
/**
* 代理商id
*/
@ApiModelProperty(value = "代理商id")
@TableField("agent_id")
private Long agentId;
/**
* 学校id
*/
@ApiModelProperty(value = "学校id")
@TableField("school_id")
private Long schoolId;
/**
* 启用状态. 0:未启用, 1:已启用
* {@link EnableStatusEnum}
*/
@ApiModelProperty(value = "启用状态. 0:未启用, 1:已启用")
@TableField("enable_status")
private Integer enableStatus;
}

View File

@ -0,0 +1,77 @@
package com.yida.data.common.core.entity.agent;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@ApiModel("区域后台微信公众号信息接收人")
@Data
public class EduAgentWxPublicReceiver {
/**
* 主键id
*/
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 是否删除1删除0未删除默认0
*/
@ApiModelProperty(value = "是否删除1删除0未删除默认0")
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@ApiModelProperty(value = "创建人id")
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 最后修改时间
*/
@ApiModelProperty(value = "最后修改时间")
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 最后修改人id
*/
@ApiModelProperty(value = "最后修改人id")
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
@ApiModelProperty(value = "代理商主部门id")
private Long agentId;
@ApiModelProperty(value = "创建人部门id")
private Long createDeptId;
private String wxPublicOpenId;
private String nickname;
@ApiModelProperty("0-未知1-男2-女")
private Integer sex;
private String avatar;
}

View File

@ -0,0 +1,90 @@
package com.yida.data.common.core.entity.apply;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Data;
/**
* 应用表 Entity
*
* @author zhanghaijun
* @date 2021-06-30 15:40:49
*/
@Data
@TableName("edu_apply")
public class EduApply {
/**
*
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 应用名称
*/
@TableField("apply_name")
private String applyName;
/**
* 应用编码与前端应用相匹配
*/
@TableField("apply_code")
private String applyCode;
/**
* 是否删除1删除0未删除默认0
*/
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 修改时间
*/
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 修改人id
*/
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
/**
* 应用名字
*/
@TableField(exist = false)
private String function;
private transient List<EduApplyFunction> functionList;
}

View File

@ -0,0 +1,79 @@
package com.yida.data.common.core.entity.apply;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
* 应用的功能表 Entity
*
* @author zhanghaijun
* @date 2021-06-30 15:41:29
*/
@Data
@TableName("edu_apply_function")
public class EduApplyFunction {
/**
*
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
*
*/
@TableField("apply_id")
private Long applyId;
/**
* 功能名称
*/
@TableField("function_name")
private String functionName;
/**
* 是否删除 1删除0未删除默认0
*/
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间
*/
@TableField(value ="create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@TableField(value ="create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 修改时间
*/
@TableField(value ="update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 修改人id
*/
@TableField(value ="update_id", fill = FieldFill.UPDATE)
private Long updateId;
}

View File

@ -0,0 +1,198 @@
package com.yida.data.common.core.entity.apply;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 订单表 Entity
*
* @author zhanghaijun
* @date 2021-07-20 13:36:37
*/
@Data
@TableName("edu_apply_product_order")
public class EduApplyProductOrder {
/**
*
*/
@TableId(value = "order_id", type = IdType.AUTO)
private Long orderId;
/**
* 订单编号:NOT NULL不可重复加索引生成规则参照snowflake算法原理生成
*/
@TableField("order_code")
private String orderCode;
/**
* 流水号生成规则
* 第一位Z
* 第2-10位学校ID缺少的以0在前补位
* 第11-20位商品编码code缺少的以0在前补位
* 第21-28位购买日期年月日
* 第29-36位8位随机数
*/
@TableField("transaction_number")
private String transactionNumber;
/**
* 商品id
*/
@TableField("product_id")
private Long productId;
/**
* 商品名称
*/
@TableField("product_name")
private String productName;
/**
* 商品单价
*/
@TableField("product_price")
private Double productPrice;
/**
* 商品总价
*/
@TableField("product_total_price")
private Double productTotalPrice;
/**
* 商品数量
*/
@TableField("product_num")
private Integer productNum;
/**
* 实际支付金额
*/
@TableField("pracctical_money")
private Double praccticalMoney;
/**
* 支付人手机号家长手机
*/
@TableField("Phone")
private String phone;
/**
* 支付时间
*/
@TableField("pay_date")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime payDate;
/**
* 订单状态0待付款
* 1付款中
* 2交易完成正常支付成功
* 3待退款
* 4交易关闭a:超时未支付,b:退款成功
*/
@TableField("order_status")
private String orderStatus;
/**
* 支付状态0未支付(默认)
* 1已支付
* 2已退款
* 3已取消
*/
@TableField("pay_status")
private String payStatus;
/**
* 支付方式1微信2支付宝3银联4其他待定
*/
@TableField("pay_way")
private String payWay;
/**
* 是否退款0默认
* 1
*/
@TableField("is_refund")
private String isRefund;
/**
* 是否删除1删除
* 0未删除 默认0
*/
@TableField("del_flag")
@TableLogic(value = "0", delval = "1")
private Integer delFlag;
/**
* 创建时间下单时间
*/
@TableField(value = "create_date", fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createDate;
/**
* 创建人id
*/
@TableField(value = "create_id", fill = FieldFill.INSERT)
private Long createId;
/**
* 修改时间
*/
@TableField(value = "update_date", fill = FieldFill.UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
/**
* 修改人id
*/
@TableField(value = "update_id", fill = FieldFill.UPDATE)
private Long updateId;
/**
* 年级+班级
*/
@TableField(exist = false)
private String gradeClass;
/**
* 学校名字
*/
@TableField(exist = false)
private String schoolName;
/**
* 学生名字
*/
@TableField(exist = false)
private String studentName;
/**
* 该笔订单包含的学生
*/
private transient List<EduApplyProductOrderStudent> orderStudentList;
@ApiModelProperty("退款信息")
private transient EduApplyProductRefund refund;
/**
* 该笔订单包含的学生
*/
private transient String studentList;
private transient Long schoolId;
}

Some files were not shown because too many files have changed in this diff Show More