zhoux 2 lat temu
commit
05c1f8f5e1
65 zmienionych plików z 4818 dodań i 0 usunięć
  1. 44 0
      .gitignore
  2. 0 0
      README.md
  3. 249 0
      pom.xml
  4. 5 0
      src/main/docker/Dockerfile
  5. 30 0
      src/main/java/com/dk/oauth/OauthServer.java
  6. 175 0
      src/main/java/com/dk/oauth/config/ShiroServerConfig.java
  7. 65 0
      src/main/java/com/dk/oauth/controller/AuthAccessTokenController.java
  8. 98 0
      src/main/java/com/dk/oauth/controller/AuthClientController.java
  9. 63 0
      src/main/java/com/dk/oauth/controller/AuthCodeController.java
  10. 336 0
      src/main/java/com/dk/oauth/controller/oauth/AccessTokenController.java
  11. 34 0
      src/main/java/com/dk/oauth/controller/oauth/AppLoginContrller.java
  12. 175 0
      src/main/java/com/dk/oauth/controller/oauth/AuthorizeController.java
  13. 66 0
      src/main/java/com/dk/oauth/controller/oauth/LogoutController.java
  14. 96 0
      src/main/java/com/dk/oauth/controller/oauth/UserInfoController.java
  15. 64 0
      src/main/java/com/dk/oauth/dto/AuthAccessTokenDto.java
  16. 65 0
      src/main/java/com/dk/oauth/dto/AuthClientDto.java
  17. 52 0
      src/main/java/com/dk/oauth/dto/AuthCodeDto.java
  18. 66 0
      src/main/java/com/dk/oauth/dto/AuthUserLoginLogDto.java
  19. 73 0
      src/main/java/com/dk/oauth/entity/AuthAccessToken.java
  20. 79 0
      src/main/java/com/dk/oauth/entity/AuthClient.java
  21. 68 0
      src/main/java/com/dk/oauth/entity/AuthCode.java
  22. 96 0
      src/main/java/com/dk/oauth/entity/AuthUserLoginLog.java
  23. 20 0
      src/main/java/com/dk/oauth/feign/service/UserFeignService.java
  24. 22 0
      src/main/java/com/dk/oauth/feign/service/impl/UserFeignServiceImpl.java
  25. 26 0
      src/main/java/com/dk/oauth/mapper/AuthAccessTokenMapper.java
  26. 20 0
      src/main/java/com/dk/oauth/mapper/AuthClientMapper.java
  27. 20 0
      src/main/java/com/dk/oauth/mapper/AuthCodeMapper.java
  28. 20 0
      src/main/java/com/dk/oauth/mapper/AuthUserLoginLogMapper.java
  29. 19 0
      src/main/java/com/dk/oauth/service/IAuthAccessTokenService.java
  30. 17 0
      src/main/java/com/dk/oauth/service/IAuthClientService.java
  31. 17 0
      src/main/java/com/dk/oauth/service/IAuthCodeService.java
  32. 17 0
      src/main/java/com/dk/oauth/service/IAuthUserLoginLogService.java
  33. 52 0
      src/main/java/com/dk/oauth/service/impl/AuthAccessTokenServiceImpl.java
  34. 43 0
      src/main/java/com/dk/oauth/service/impl/AuthClientServiceImpl.java
  35. 44 0
      src/main/java/com/dk/oauth/service/impl/AuthCodeServiceImpl.java
  36. 43 0
      src/main/java/com/dk/oauth/service/impl/AuthUserLoginLogServiceImpl.java
  37. 26 0
      src/main/java/com/dk/oauth/shiro/credentials/JWTCredentialsMatcher.java
  38. 86 0
      src/main/java/com/dk/oauth/shiro/filter/OAuth2AuthenticationFilter.java
  39. 33 0
      src/main/java/com/dk/oauth/shiro/jwt/JWTGenerator.java
  40. 102 0
      src/main/java/com/dk/oauth/shiro/jwt/JWTToken.java
  41. 15 0
      src/main/java/com/dk/oauth/shiro/realm/CustomeRealm.java
  42. 95 0
      src/main/java/com/dk/oauth/shiro/realm/JWTClientRealm.java
  43. 52 0
      src/main/java/com/dk/oauth/shiro/realm/JWTModularRealmAuthenticator.java
  44. 105 0
      src/main/java/com/dk/oauth/shiro/realm/JWTRealm.java
  45. 9 0
      src/main/java/com/dk/oauth/shiro/test/TestUserPassword.java
  46. 69 0
      src/main/java/com/dk/oauth/util/AESSecurityUtil.java
  47. 194 0
      src/main/java/com/dk/oauth/util/DateUtil.java
  48. 135 0
      src/main/java/com/dk/oauth/util/IpUtil.java
  49. 273 0
      src/main/java/com/dk/oauth/util/JwtUtil.java
  50. 45 0
      src/main/java/com/dk/oauth/util/PassWordUtil.java
  51. 38 0
      src/main/java/com/dk/oauth/util/SaltUtil.java
  52. 54 0
      src/main/java/com/dk/oauth/util/UUID.java
  53. 115 0
      src/main/resources/dev/bootstrap.yml
  54. 191 0
      src/main/resources/logback-spring.xml
  55. 80 0
      src/main/resources/mapper/AuthAccessTokenMapper.xml
  56. 85 0
      src/main/resources/mapper/AuthClientMapper.xml
  57. 49 0
      src/main/resources/mapper/AuthCodeMapper.xml
  58. 77 0
      src/main/resources/mapper/AuthUserLoginLogMapper.xml
  59. 8 0
      src/main/resources/mybatis-config.xml
  60. 19 0
      src/main/resources/prod/bootstrap.yml
  61. 117 0
      src/main/resources/st/bootstrap.yml
  62. 117 0
      src/main/resources/test/bootstrap.yml
  63. 19 0
      src/main/resources/uat/bootstrap.yml
  64. 106 0
      src/main/webapp/WEB-INF/views/login.jsp
  65. 125 0
      src/main/webapp/WEB-INF/views/oauth2login.jsp

+ 44 - 0
.gitignore

@@ -0,0 +1,44 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+logs
+.idea
+*.log
+》
+*.iws
+*.ipr
+*.iml
+*.gz
+*.tmp
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
+docs/04_ci_script/
+hegii-product/hegii-product-provider/src/test/
+iap-auth/src/
+iap-common/iap-common-core/src/test/
+iap-common/iap-common-util/src/test/
+iap-gateway/src/test/
+iap-ops/src/
+/dev_jco_rfc.trc

+ 0 - 0
README.md


+ 249 - 0
pom.xml

@@ -0,0 +1,249 @@
+<?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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.dk.iboss</groupId>
+    <artifactId>iboss-server-oauth</artifactId>
+    <version>3.0.0</version>
+    <name>iboss-server-oauth</name>
+    <description>dk iboss oauth server</description>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.6.RELEASE</version>
+        <relativePath/>
+    </parent>
+
+    <properties>
+        <com.alibaba.druid.version>1.1.21</com.alibaba.druid.version>
+        <mybatis-plus-boot-starter.version>3.0-RC3</mybatis-plus-boot-starter.version>
+        <spring.shiro.version>1.4.0</spring.shiro.version>
+        <oltu.version>1.0.0</oltu.version>
+        <servlet-api.version>3.0-alpha-1</servlet-api.version>
+        <javax.servlet.jsp-api.version>2.3.1</javax.servlet.jsp-api.version>
+    </properties>
+
+    <profiles>
+        <profile>
+            <id>st</id>
+            <properties>
+                <environment>st</environment>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>uat</id>
+            <properties>
+                <environment>uat</environment>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>prod</id>
+            <properties>
+                <environment>prod</environment>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>test</id>
+            <properties>
+                <environment>test</environment>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>dev</id>
+            <properties>
+                <environment>dev</environment>
+            </properties>
+            <activation>
+                <activeByDefault>true</activeByDefault><!-- 默认激活该profile节点-->
+            </activation>
+        </profile>
+    </profiles>
+
+    <dependencies>
+        <!-- 公共模块 -->
+        <dependency>
+            <groupId>com.dk.iboss</groupId>
+            <artifactId>iboss-dependency-common</artifactId>
+            <version>3.0.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.alibaba</groupId>
+                    <artifactId>fastjson</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.vaadin.external.google</groupId>
+                    <artifactId>android-json</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.47</version>
+        </dependency>
+        <!-- JWT -->
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>3.4.1</version>
+        </dependency>
+        <!-- commons-lang3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3.version}</version>
+        </dependency>
+        <!-- shiro 关键包-->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring-boot-web-starter</artifactId>
+            <version>${spring.shiro.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
+            <version>${oltu.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.oltu.oauth2</groupId>
+            <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
+            <version>${oltu.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-ehcache</artifactId>
+            <version>${spring.shiro.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource> <!--此处配置到java是因为mapper.xml文件在java目录-->
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+            <resource> <!--项目配置文件-->
+                <directory>src/main/resources/${environment}</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource> <!--日志配置文件-->
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>com.dk.oauth.OauthServer</mainClass>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>1.2.2</version>
+
+                <configuration>
+                    <serverId>aliyun-acr</serverId>
+                    <registryUrl>registry.cn-shenzhen.aliyuncs.com</registryUrl>
+                    <!--依赖的基础镜像-->
+                    <baseImage>java</baseImage>
+                    <forceTags>true</forceTags>    <!--覆盖相同标签镜像-->
+                    <!--imageName必须跟仓库路径一致-->
+                    <imageName>registry.cn-shenzhen.aliyuncs.com/hgscrm-${environment}/${project.artifactId}:${project.version}</imageName>
+                    <!-- 指定Dockerfile所在的路径 -->
+                    <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
+                    <resources>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}</directory>
+                            <include>${project.build.finalName}.jar</include>
+                        </resource>
+                    </resources>
+                    <pushImage>true</pushImage>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+    <repositories>
+<!--        <repository>-->
+<!--            &lt;!&ndash;恒洁maven私服 haip仓库&ndash;&gt;-->
+<!--            <id>private</id>-->
+<!--            <name>private</name>-->
+<!--            <url>http://172.17.216.67:8081/repository/haip</url>-->
+<!--            <releases>-->
+<!--                <enabled>true</enabled>-->
+<!--            </releases>-->
+<!--            <snapshots>-->
+<!--                <enabled>true</enabled>-->
+<!--            </snapshots>-->
+<!--        </repository>-->
+
+        <!--maven私服 setting.xml 配置
+        <server>
+            <id>haip</id>
+            <username>haip</username>
+            <password>haip2020</password>
+        </server>-->
+        <!--阿里云仓库-->
+        <repository>
+            <id>aliyun</id>
+            <name>aliyun</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <!--中央仓库-->
+        <repository>
+            <id>central</id>
+            <name>central</name>
+            <url>https://repo1.maven.org/maven2</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+</project>

+ 5 - 0
src/main/docker/Dockerfile

@@ -0,0 +1,5 @@
+FROM java:8
+# COPY jar from the first stage
+ADD mes-server-oauth-1.0-dev.jar mes-server-oauth.jar
+
+ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/mes-server-oauth.jar"]

+ 30 - 0
src/main/java/com/dk/oauth/OauthServer.java

@@ -0,0 +1,30 @@
+package com.dk.oauth;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @Author: dapeng
+ * @Description: 启动类
+ * @Date: create in 2022/6/28 15:58
+ */
+@RefreshScope
+@EnableSwagger2
+@EnableDiscoveryClient
+@MapperScan(basePackages = {"com.dk.oauth.mapper","com.dk.common.mapper.opinfo"})
+@EnableFeignClients
+@SpringBootApplication
+@ComponentScan(basePackages = {"com.dk.common","com.dk.oauth"})
+public class OauthServer {
+
+    public static void main(String[] args) {
+        SpringApplication.run(OauthServer.class, args);
+    }
+
+}

+ 175 - 0
src/main/java/com/dk/oauth/config/ShiroServerConfig.java

@@ -0,0 +1,175 @@
+package com.dk.oauth.config;
+
+import com.dk.oauth.shiro.credentials.JWTCredentialsMatcher;
+import com.dk.oauth.shiro.filter.OAuth2AuthenticationFilter;
+import com.dk.oauth.shiro.realm.JWTClientRealm;
+import com.dk.oauth.shiro.realm.JWTModularRealmAuthenticator;
+import com.dk.oauth.shiro.realm.JWTRealm;
+import org.apache.shiro.authc.credential.CredentialsMatcher;
+import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
+import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
+import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
+import org.apache.shiro.mgt.DefaultSubjectDAO;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.CookieRememberMeManager;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Filter;
+import java.util.*;
+
+@Configuration
+public class ShiroServerConfig {
+
+    // 注意/r/n前不能有空格
+    private static final String CRLF = "\r\n";
+
+    @Bean
+    public JWTRealm jwtRealm(CredentialsMatcher matcher) {
+        JWTRealm JWTRealm = new JWTRealm();
+        JWTRealm.setCredentialsMatcher(matcher);
+        return JWTRealm;
+    }
+
+    @Bean
+    public JWTClientRealm jwtClientRealm(CredentialsMatcher matcher) {
+        JWTClientRealm jwtClientRealm = new JWTClientRealm();
+        jwtClientRealm.setCredentialsMatcher(matcher);
+        return jwtClientRealm;
+    }
+
+    @Bean
+    public CredentialsMatcher credentialsMatcher() {
+        return new JWTCredentialsMatcher();
+    }
+
+    @Bean(name = "securityMananger")
+    public DefaultWebSecurityManager securityManager(CredentialsMatcher matcher) {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        //设置realm.
+        securityManager.setAuthenticator(modularRealmAuthenticator());
+        List<Realm> realms = new ArrayList<>();
+        realms.add(jwtRealm(matcher));
+        realms.add(jwtClientRealm(matcher));
+        securityManager.setRealms(realms);
+//        securityManager.setRealm(jwtRealm(matcher));
+        /*
+         * 关闭shiro自带的session,详情见文档
+         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
+         */
+        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
+        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
+        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
+        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
+        securityManager.setSubjectDAO(subjectDAO);
+        return securityManager;
+    }
+
+    /**
+     * 系统自带的Realm管理,主要针对多realm
+     */
+    @Bean
+    public ModularRealmAuthenticator modularRealmAuthenticator() {
+        //自己重写的ModularRealmAuthenticator
+        JWTModularRealmAuthenticator modularRealmAuthenticator = new JWTModularRealmAuthenticator();
+        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
+        return modularRealmAuthenticator;
+    }
+
+    @Bean(name = "rememberCookies")
+    public SimpleCookie createSimpleCookies() {
+        SimpleCookie sc = new SimpleCookie("rememberMe");
+        sc.setHttpOnly(true);
+        sc.setMaxAge(5);
+        return sc;
+    }
+
+    @Bean(name = "cookieRemmberMananger")
+    public CookieRememberMeManager createCookieRemmberMananger() {
+        CookieRememberMeManager crm = new CookieRememberMeManager();
+        crm.setCookie(createSimpleCookies());
+        return crm;
+    }
+
+    /*@Bean(name = "cacheManager")
+    public EhCacheManager createEhcacheManager() {
+        EhCacheManager cacheManager = new EhCacheManager();
+        String path = "classpath:ehcache.xml";
+        cacheManager.setCacheManagerConfigFile(path);
+        return cacheManager;
+    }*/
+
+    /**
+     * 读取ini文获得固定权限
+     */
+    public String loadFilterChainDefinitions() {
+        StringBuffer sb = new StringBuffer();
+        //	sb.append(getFixedAuthRule());//固定权限,采用读取配置文件
+       /* sb.append("/ = anon").append(CRLF);
+        sb.append("/login = anon").append(CRLF);
+        sb.append("/logout = logout").append(CRLF);
+        sb.append("/authorize=anon").append(CRLF);
+        sb.append("/accessToken=anon").append(CRLF);
+        sb.append("/authClient/** = anon").append(CRLF);*/
+        sb.append("/userInfo = oauth2AuthenticationFilter").append(CRLF);
+//        sb.append("/swagger/** = anon").append(CRLF);
+//        sb.append("/v2/api-docs = anon").append(CRLF);
+//        sb.append("/swagger-ui.html = anon").append(CRLF);
+//        sb.append("/swagger-resources/** = anon").append(CRLF);
+//        sb.append("/** = user").append(CRLF);
+        return sb.toString();
+    }
+
+
+    @Bean(name = "shiroFilterFactoryBean")
+    public ShiroFilterFactoryBean createShiroSecurityFilterFactory() {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        shiroFilterFactoryBean.setSecurityManager(securityManager(credentialsMatcher()));
+        shiroFilterFactoryBean.setLoginUrl("/login");
+        Map filterChainDefinitionMap = new HashMap<String, String>();
+        //注意过滤器配置顺序 不能颠倒
+//        filterChainDefinitionMap.put("/userInfo/**", "authc");
+  /*     filterChainDefinitionMap.put("/static/**", "anon");
+         filterChainDefinitionMap.put("/templates/**", "anon");
+         filterChainDefinitionMap.put("/g/unLogin", "anon");
+         filterChainDefinitionMap.put("/g/login", "loginFtr");
+         filterChainDefinitionMap.put("/g/logout", "authc");
+         filterChainDefinitionMap.put("/g/unauthorized", "anon");
+         filterChainDefinitionMap.put("/**", "permsFilter");*/
+        // 添加自己的过滤器并且取名为jwt
+        LinkedHashMap<String, Filter> filterMap = new LinkedHashMap<>();
+        filterMap.put("oauth2AuthenticationFilter", oauth2AuthenticationFilter());
+        shiroFilterFactoryBean.setFilters(filterMap);
+        // 过滤链定义,从上向下顺序执行,一般将放在最为下边
+        filterChainDefinitionMap.put("/**", "oauth2AuthenticationFilter");
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
+        shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean
+    public OAuth2AuthenticationFilter oauth2AuthenticationFilter() {
+        OAuth2AuthenticationFilter authFilter = new OAuth2AuthenticationFilter();
+        authFilter.setAuthcCodeParam("code");
+        return authFilter;
+    }
+
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(CredentialsMatcher matcher) {//@Qualifier("hashedCredentialsMatcher")
+        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
+        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager(matcher));
+        return authorizationAttributeSourceAdvisor;
+    }
+
+    @Bean
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
+        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
+        return defaultAdvisorAutoProxyCreator;
+    }
+}

+ 65 - 0
src/main/java/com/dk/oauth/controller/AuthAccessTokenController.java

@@ -0,0 +1,65 @@
+package com.dk.oauth.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthAccessTokenDto;
+import com.dk.oauth.entity.AuthAccessToken;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * (IapAuthAccessTokenT)表控制层
+ *
+ * @author iAP
+ * @since 2020-06-17 19:49:15
+ */
+@RestController
+@RequestMapping("/authAccessToken")
+public class AuthAccessTokenController {
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 服务对象
+     */
+    @Autowired
+    private IAuthAccessTokenService authAccessTokenService;
+
+    @PostMapping("/add")
+    @ApiOperation(value = "新增记录", notes = "新增记录")
+    public ResponseResultVO add(@RequestBody AuthAccessToken authAccessToken) {
+        logger.info("IapAuthAccessTokenTDto add Record...");
+        return ResponseResultUtil.success(authAccessTokenService.saveOrUpdate(authAccessToken));
+    }
+
+    @PostMapping("/delete")
+    @ApiOperation(value = "根据ID删除记录", notes = "根据ID删除记录")
+    public ResponseResultVO delete(@RequestBody AuthAccessToken authAccessToken) {
+        logger.info("IapAuthAccessTokenTDto delete Record...");
+        return ResponseResultUtil.success(authAccessTokenService.remove(new QueryWrapper<AuthAccessToken>().lambda()
+                .eq(AuthAccessToken::getTokenId, authAccessToken.getTokenId())));
+    }
+
+    @PostMapping("/update")
+    @ApiOperation(value = "根据ID修改记录", notes = "根据ID修改记录")
+    public ResponseResultVO update(@RequestBody AuthAccessToken authAccessToken) {
+        logger.info("IapAuthAccessTokenTDto updateRecord...");
+        return ResponseResultUtil.success(authAccessTokenService.updateById(authAccessToken));
+    }
+
+    @PostMapping("/queryData")
+    @ApiOperation(value = "分页查询", notes = "分页查询")
+    public ResponseResultVO queryRecord(@RequestBody AuthAccessTokenDto authAccessTokenDto) {
+        logger.info("IapAuthAccessTokenTDto queryRecord...");
+        return ResponseResultUtil.success(authAccessTokenService.pageQuery(authAccessTokenDto));
+    }
+
+}

+ 98 - 0
src/main/java/com/dk/oauth/controller/AuthClientController.java

@@ -0,0 +1,98 @@
+package com.dk.oauth.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthClientDto;
+import com.dk.oauth.entity.AuthAccessToken;
+import com.dk.oauth.entity.AuthClient;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import com.dk.oauth.service.IAuthClientService;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.dk.oauth.util.UUID;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+/**
+ * (IapAuthClientT)表控制层
+ *
+ * @author iAP
+ * @since 2020-06-17 19:49:17
+ */
+@RestController
+@RequestMapping("/authClient")
+public class AuthClientController {
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 服务对象
+     */
+    @Autowired
+    private IAuthClientService authClientService;
+    @Autowired
+    private IAuthAccessTokenService authAccessTokenService;
+
+    @PostMapping("/add")
+    @ApiOperation(value = "新增记录", notes = "新增记录")
+    public String add(@RequestBody AuthClient authClient) {
+        logger.info("IapAuthClientTDto add Record...");
+        String clientId = UUID.uuid32();
+        authClient.setCreateDate(new Date());
+        authClient.setLastUpdateDate(new Date());
+        authClient.setClientId(clientId);
+        authClient.setClientSecret(UUID.uuid32());
+        authClientService.saveOrUpdate(authClient);
+        return authClient.getId();
+    }
+
+    @PostMapping("/delete")
+    @ApiOperation(value = "根据ID删除记录", notes = "根据ID删除记录")
+    public ResponseResultVO delete(@RequestBody AuthClient authClient) {
+        logger.info("IapAuthClientTDto delete Record...");
+        return ResponseResultUtil.success(authClientService.removeById(authClient.getId()));
+    }
+
+    @PostMapping("/deleteByIdList")
+    @ApiOperation(value = "根据ID删除记录", notes = "根据ID删除记录")
+    public ResponseResultVO deleteByIdList(@RequestBody String[] ids) {
+        logger.info("IapAuthClientTDto deleteBatch Record...");
+        List<String> list = Arrays.asList(ids);
+        ArrayList<String> arrayList = new ArrayList<String>(list);
+        return ResponseResultUtil.success(authClientService.removeByIds(arrayList));
+    }
+
+    @PostMapping("/update")
+    @ApiOperation(value = "根据ID修改记录", notes = "根据ID修改记录")
+    public ResponseResultVO update(@RequestBody AuthClient authClient) {
+        logger.info("IapAuthClientTDto updateRecord...");
+        if (authClient.getState() != null && authClient.getState().equals(AuthClientDto.STATE_1)) {
+            authAccessTokenService.remove(new QueryWrapper<AuthAccessToken>().eq("client_id", authClient.getClientId()));
+        }
+        return ResponseResultUtil.success(authClientService.updateById(authClient));
+    }
+
+    @PostMapping("/query")
+    @ApiOperation(value = "分页查询", notes = "分页查询")
+    public ResponseResultVO queryRecord(@RequestBody AuthClientDto authClientDto) {
+        logger.info("IapAuthClientTDto queryRecord...");
+        return ResponseResultUtil.success(authClientService.pageQuery(authClientDto));
+    }
+
+    @PostMapping("/queryDetail")
+    @ApiOperation(value = "详情查询", notes = "详情查询")
+    public ResponseResultVO queryDetail(@RequestBody AuthClientDto authClientDto) {
+        logger.info("IapAuthClientTDto queryRecord...");
+        AuthClient authClient = new AuthClient();
+        BeanUtils.copyProperties(authClientDto, authClient);
+        return ResponseResultUtil.success(authClientService.getOne(new QueryWrapper<AuthClient>(authClient)));
+    }
+}

+ 63 - 0
src/main/java/com/dk/oauth/controller/AuthCodeController.java

@@ -0,0 +1,63 @@
+package com.dk.oauth.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthCodeDto;
+import com.dk.oauth.entity.AuthCode;
+import com.dk.oauth.service.IAuthCodeService;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * (IapAuthCodeT)表控制层
+ *
+ * @author iAP
+ * @since 2020-06-17 19:49:17
+ */
+@RestController
+@RequestMapping("/authCode")
+public class AuthCodeController {
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 服务对象
+     */
+    @Autowired
+    private IAuthCodeService authCodeService;
+
+    @PostMapping("/add")
+    @ApiOperation(value = "新增记录", notes = "新增记录")
+    public ResponseResultVO add(@RequestBody AuthCode authCode) {
+        logger.info("IapAuthCodeTDto add Record...");
+        return ResponseResultUtil.success(authCodeService.saveOrUpdate(authCode));
+    }
+
+    @PostMapping("/delete")
+    @ApiOperation(value = "根据ID删除记录", notes = "根据ID删除记录")
+    public ResponseResultVO delete(@RequestBody AuthCode authCode) {
+        logger.info("IapAuthCodeTDto delete Record...");
+        return ResponseResultUtil.success(authCodeService.remove(new QueryWrapper<AuthCode>().lambda().eq(AuthCode::getCode, authCode.getCode())));
+    }
+
+    @PostMapping("/update")
+    @ApiOperation(value = "根据ID修改记录", notes = "根据ID修改记录")
+    public ResponseResultVO update(@RequestBody AuthCode authCode) {
+        logger.info("IapAuthCodeTDto updateRecord...");
+        return ResponseResultUtil.success(authCodeService.updateById(authCode));
+    }
+
+    @PostMapping("/query")
+    @ApiOperation(value = "分页查询", notes = "分页查询")
+    public ResponseResultVO queryRecord(@RequestBody AuthCodeDto authCodeDto) {
+        logger.info("IapAuthCodeTDto queryRecord...");
+        return ResponseResultUtil.success(authCodeService.pageQuery(authCodeDto));
+    }
+}

+ 336 - 0
src/main/java/com/dk/oauth/controller/oauth/AccessTokenController.java

@@ -0,0 +1,336 @@
+package com.dk.oauth.controller.oauth;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.infrastructure.constant.Constant;
+import com.dk.common.infrastructure.enums.ErrorCodeEnum;
+import com.dk.common.model.vo.core.UserVO;
+import com.dk.common.response.ResponseCodeEnum;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.common.service.UserService;
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.entity.AuthAccessToken;
+import com.dk.oauth.entity.AuthClient;
+import com.dk.oauth.entity.AuthCode;
+import com.dk.oauth.entity.AuthUserLoginLog;
+import com.dk.oauth.mapper.AuthUserLoginLogMapper;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import com.dk.oauth.service.IAuthClientService;
+import com.dk.oauth.service.IAuthCodeService;
+import com.dk.oauth.shiro.jwt.JWTGenerator;
+import com.dk.oauth.shiro.jwt.JWTToken;
+import com.dk.oauth.util.AESSecurityUtil;
+import com.dk.oauth.util.DateUtil;
+import com.dk.oauth.util.IpUtil;
+import com.dk.oauth.util.UUID;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
+import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.shiro.SecurityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 令牌生成
+ */
+@Slf4j
+@RestController
+public class AccessTokenController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Resource
+    private IAuthCodeService authCodeService;
+    @Resource
+    private IAuthClientService authClientService;
+    @Resource
+    private IAuthAccessTokenService authAccessTokenService;
+    @Resource
+    private UserService userService;
+    @Resource
+    private AuthUserLoginLogMapper authUserLoginLogMapper;
+
+    @Value("${aes-key}")
+    private String AESKey;
+    @Value("${client-app-id}")
+    private String clientAppId;
+
+    /**
+     * @desc : 获取token
+     * @author : 周兴
+     * @date : 2023/1/5 13:35
+     */
+    @PostMapping(value = "/oauth/token")
+    public ResponseResultVO token(HttpServletRequest request) throws Exception {
+        AuthUserLoginLog authUserLoginLog = new AuthUserLoginLog();
+        AuthAccessToken authAccessToken = new AuthAccessToken();
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Content-Type", "application/json; charset=utf-8");
+        try {
+            // region 校验client参数
+
+            // 转为OAuth请求
+            OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);
+
+            // 校验客户端ID是否正确
+            QueryWrapper queryWrapper = new QueryWrapper();
+            queryWrapper.eq("client_id", oauthRequest.getClientId());
+            AuthClient client = authClientService.getOne(queryWrapper);
+            if (null == client) {
+                log.error("获取accessToken时,客户端ID错误 client=" + oauthRequest.getClientId());
+                return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CLIENT_DESCRIPTION);
+            }
+
+            // 校验客户端安全KEY是否正确
+            if (!oauthRequest.getClientSecret().equalsIgnoreCase(client.getClientSecret())) {
+                log.error("ClientSecret不合法 client_secret=" + oauthRequest.getClientSecret());
+                return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CLIENT_DESCRIPTION);
+            }
+
+            // 校验authCode
+            String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
+            AuthCode code = authCodeService.getOne(new QueryWrapper<AuthCode>().eq("code", authCode));
+            if (client.getState() != null && client.getState().equals(AuthCode.STATE_1)) {
+                return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CLIENT_STOP);
+            }
+            authUserLoginLog.setClient(authCode);
+            //endregion
+
+            // region 根据不同grant_type处理
+            /**
+             * 只校验 AUTHORIZATION_CODE、PASSWORD 、REFRESH_TOKEN 和 CLIENT_CREDENTIALS 类型
+             * 具体查看 {@link GrantType}
+             * */
+            UserVO userVo = null;
+            //定义api用户
+            UserVO apiUser = null;
+            ResponseResultVO validRes = ResponseResultUtil.error(ResponseCodeEnum.OPERATE_FAIL);
+
+            // region AUTHORIZATION_CODE
+            if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
+                if (!code.getCode().equals(authCode)) {
+                    authUserLoginLog.setLoginType(AuthUserLoginLog.LOGIN_TYPE0);
+                    authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+                    loinLog(authUserLoginLog, request);
+                    log.error("获取accessToken时,授权码错误");
+                    return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CODE_DESCRIPTION);
+                }
+                authAccessToken.setUserId(code.getUserId());
+            }
+            // endregion
+
+            // region PASSWORD
+            else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equalsIgnoreCase(GrantType.PASSWORD.toString())) {
+                UserVO user = new UserVO();
+                user.setUserCode(request.getParameter("username")).setUserPwd(request.getParameter("password"))
+                        .setAppCode(request.getParameter("appcode")).setFtyCode(request.getParameter("ftycode"));
+//                ResponseResultVO<UserVO> userRes = userService.selectCpCodeByCodeOrPhone(request.getParameter("username"));
+//                if (userRes.getCode() == ResponseCodeEnum.SUCCESS.getCode()) {
+//                    user = userRes.getData();
+//                } else {
+//                    return userRes;
+//                }
+                //调用user服务进行业务校验
+                validRes = userService.loginValid(user);
+                if (validRes.getCode() != ResponseCodeEnum.SUCCESS.getCode()) {
+                    authUserLoginLog.setLoginType(AuthUserLoginLog.LOGIN_TYPE3);
+                    authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+                    loinLog(authUserLoginLog, request);
+                    return validRes;
+                } else {
+                    userVo = JSON.parseObject(JSON.toJSONString(validRes.getData())).getObject("user", UserVO.class);
+                    authAccessToken.setUserId(String.valueOf(userVo.getUserId()));
+                }
+            }
+            // endregion
+
+            // region REFRESH_TOKEN
+            else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.REFRESH_TOKEN.toString())) {
+                // 不允许刷新TOKEN模式
+                authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+                loinLog(authUserLoginLog, request);
+                return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_GRAND_TYPE_NOTFOUND);
+            }
+            // endregion
+
+            // region CLIENT_CREDENTIALS
+            else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.CLIENT_CREDENTIALS.toString())) {
+                // 判断客户端身份
+                boolean isClientCredential = false;
+                String[] grantTypes = client.getGrantTypes().split(",");
+                for (String grantType : grantTypes) {
+                    if (grantType.equals(GrantType.CLIENT_CREDENTIALS.toString())) {
+                        isClientCredential = true;
+                        break;
+                    }
+                }
+                // 如果该客户端不允许使用客户端模式登陆
+                if (!isClientCredential) {
+                    authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+                    loinLog(authUserLoginLog, request);
+                    // 不允许客户端模式登陆
+                    return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CLIENT_DESCRIPTION);
+                }
+                //根据客户端主键id查询用户
+                apiUser = userService.selectByClientId(client.getId());
+                //如果不存在,或已经停用
+                if (apiUser == null || !apiUser.getFlgValid()) {
+                    return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_CLIENT_STOP);
+                }
+                authAccessToken.setUserId(String.valueOf(apiUser.getUserId()));
+            }
+            // endregion
+            else {
+                authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+                loinLog(authUserLoginLog, request);
+                return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), OauthConstants.INVALID_GRAND_TYPE_NOTFOUND);
+            }
+            // endregion
+
+            // region 开始生成Access Token
+            String username = "";
+            String userId = "";
+            if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.CLIENT_CREDENTIALS.toString())) {
+                // 客户端凭证
+                username = client.getClientId();
+                userId = String.valueOf(apiUser.getUserId());
+            } else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
+                // auth2 code模式
+                username = code.getUserId();
+                userId = code.getUserId();
+            } else {
+                // 密码模式
+                username = request.getParameter("username");
+                userId = String.valueOf(userVo.getUserId());
+            }
+            String lang = request.getParameter("lang");
+            // 应用编码
+            String appCode = request.getParameter("appcode");
+            String ftyCode = userVo.getFtyCode();
+            JWTGenerator jwtGenerator = new JWTGenerator();
+            jwtGenerator.setSalt(username);
+            jwtGenerator.setUsername(username);
+            jwtGenerator.setUserId(userId);
+            jwtGenerator.setFtyId(userVo.getFtyId().toString());
+            jwtGenerator.setFtyCode(ftyCode);
+            jwtGenerator.setClientId(client.getClientId());
+            jwtGenerator.setGrantType(oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE));
+            jwtGenerator.setAppCode(appCode);
+            jwtGenerator.setLang(lang);
+            OAuthIssuerImpl oAuthIssuer = new OAuthIssuerImpl(jwtGenerator);
+            String accessToken = oAuthIssuer.accessToken();
+            log.info("服务器生成的accessToken=" + accessToken);
+
+            // 保存token
+            authAccessToken.setId(UUID.uuid32());
+            authAccessToken.setClientId(client.getClientId());
+            authAccessToken.setTokenId(accessToken);
+            authAccessToken.setTokenType(oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE));
+            authAccessToken.setCreateDate(new Date());
+            authAccessToken.setAuthenticationId(authCode);
+            authAccessToken.setTokenExpiredSeconds(OauthConstants.EXPIRES_IN);
+            authAccessToken.setFtyId(userVo.getFtyId().toString());
+            authAccessToken.setFtyCode(userVo.getFtyCode());
+            log.info("---->>>SecurityUtils.getSubject().isAuthenticated() = " + SecurityUtils.getSubject().isAuthenticated());
+            JWTToken jwtToken = JWTToken.build(accessToken, username, userVo.getFtyId().toString(), ftyCode, username, OauthConstants.EXPIRES_IN, oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE), client.getClientId(),lang);
+            SecurityUtils.getSubject().login(jwtToken);
+            authAccessTokenService.save(authAccessToken);
+            if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
+                // 设置code失效,每个code只能使用一次
+                code.setState(1);
+                authCodeService.saveOrUpdate(code);
+                log.info("服务器移除auth_code=" + authCode);
+            }
+            // endregion
+
+            // region 加密accessToken
+            try {
+                accessToken = AESSecurityUtil.encrypt(AESKey, accessToken);
+            } catch (Exception e) {
+                logger.error("sorry,accessToken({}) encode faild!!", accessToken);
+            }
+            authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND1);
+            loinLog(authUserLoginLog, request);
+            // endregion
+
+            if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equalsIgnoreCase(GrantType.PASSWORD.toString())) {
+                //调用 loginAfterCheckPassword
+                ResponseResultVO<JSONObject> loginRes = userService.loginAfterCheckPassword(JSON.parseObject(JSON.toJSONString(validRes.getData())).fluentPut("accessToken", accessToken));
+
+                return ResponseResultUtil.success(JSON.parseObject(JSON.toJSONString(loginRes.getData(), SerializerFeature.WRITE_MAP_NULL_FEATURES))
+                        .fluentPut("nowDate", DateUtil.dateToString(authAccessToken.getCreateDate()))
+                        .fluentPut("expires_in", String.valueOf(OauthConstants.EXPIRES_IN)));
+            } else {
+                // region 生成OAuth响应
+                OAuthResponse response = OAuthASResponse
+                        .tokenResponse(HttpServletResponse.SC_OK)
+                        .setAccessToken(accessToken)
+                        .setExpiresIn(String.valueOf(OauthConstants.EXPIRES_IN))
+                        .setParam("nowDate", DateUtil.dateToString(authAccessToken.getCreateDate()))
+                        .setParam("appCode",appCode)
+//                    .setParam("username", username)
+//                    .setParam("companyId", companyId)
+                        .buildJSONMessage();
+                log.info("---->>>SecurityUtils.getSubject().isAuthenticated() =" + SecurityUtils.getSubject().isAuthenticated());
+                return ResponseResultUtil.success(response.getResponseStatus(), "", JSONObject.parse(response.getBody()));
+                // endregion
+            }
+
+        } catch (OAuthProblemException e) {
+            log.error("获取accessToken发生异常=", e);
+            authUserLoginLog.setCommand(AuthUserLoginLog.LOGIN_COMMAND3);
+            loinLog(authUserLoginLog, request);
+            return ResponseResultUtil.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
+        }
+    }
+
+    /**
+     * 保存登录日志
+     *
+     * @param authUserLoginLog
+     * @param request
+     */
+    private void loinLog(AuthUserLoginLog authUserLoginLog, HttpServletRequest request) {
+        Date date = new Date();
+        authUserLoginLog.setCreateDate(date);
+        authUserLoginLog.setLastUpdateDate(date);
+        authUserLoginLog.setId(UUID.uuid32());
+        // 获取ip地址
+        String ipAddr = IpUtil.getIpAddr(request);
+        authUserLoginLog.setLastIp(ipAddr);
+        // 获取浏览器信息
+        String browser = IpUtil.getBrowser(request.getHeader("user-agent"));
+        authUserLoginLog.setVersion("1.0");
+        authUserLoginLog.setClient(browser);
+        authUserLoginLogMapper.insert(authUserLoginLog);
+    }
+
+    /**
+     * @desc : 查询用户最新token
+     * @author : 洪旭东
+     * @date : 2022-08-02 18:44
+     */
+    @PostMapping(value = "current_token/{userId}")
+    public String getCurrentToken(@PathVariable Long userId) {
+        return authAccessTokenService.getCurrentToken(userId);
+    }
+}

+ 34 - 0
src/main/java/com/dk/oauth/controller/oauth/AppLoginContrller.java

@@ -0,0 +1,34 @@
+package com.dk.oauth.controller.oauth;
+
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *  登录
+ *
+ * @author iAP
+ * @since 2020-06-17 19:49:17
+ */
+@RestController
+@RequestMapping("/login")
+public class AppLoginContrller {
+    /**
+     *  app登录接口 调用就成功
+     */
+    @PostMapping("/login")
+    public ResponseResultVO applogin(HttpServletRequest request) throws OAuthSystemException {
+        return ResponseResultUtil.success("");
+    }
+
+
+
+}

+ 175 - 0
src/main/java/com/dk/oauth/controller/oauth/AuthorizeController.java

@@ -0,0 +1,175 @@
+package com.dk.oauth.controller.oauth;
+
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.entity.AuthClient;
+import com.dk.oauth.entity.AuthCode;
+import com.dk.oauth.service.IAuthClientService;
+import com.dk.oauth.service.IAuthCodeService;
+import com.dk.oauth.shiro.jwt.JWTToken;
+import com.dk.oauth.util.JwtUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.as.issuer.MD5Generator;
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
+import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.OAuth;
+import org.apache.oltu.oauth2.common.error.OAuthError;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.common.message.types.ResponseType;
+import org.apache.oltu.oauth2.common.utils.OAuthUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+
+/**
+ * 授权处理类
+ */
+@Controller
+@Slf4j
+public class AuthorizeController {
+
+    @Autowired
+    private IAuthCodeService authCodeService;
+
+    @Autowired
+    private IAuthClientService clientService;
+
+    @GetMapping(value = "/authorize")
+    public Object authroize(Model model, HttpServletRequest request) throws OAuthSystemException, URISyntaxException {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Content-Type", "application/json; charset=utf-8");
+        try {
+            // 构建OAuth 授权请求`
+            OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
+            // 检查传入的客户端ID是否正确
+            AuthClient client = clientService.getById(oauthRequest.getClientId());
+            if (null == client) {
+                log.error("校验客户端ID失败,ClientID=" + oauthRequest.getClientId());
+                OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
+                        .setError(OAuthError.TokenResponse.INVALID_CLIENT)
+                        .setErrorDescription(OauthConstants.INVALID_CLIENT_DESCRIPTION)
+                        .buildBodyMessage();
+                return new ResponseEntity<>(response.getBody(), headers, HttpStatus.valueOf(response.getResponseStatus()));
+            }
+            if (client.getState() != null && client.getState().equals(AuthCode.STATE_1)) {
+                throw new OAuthSystemException("客户端已停止使用,请联系管理员");
+            }
+            // 校验客户端跳转地址
+            if (!client.getRedirectUri().equalsIgnoreCase(oauthRequest.getRedirectURI())) {
+                log.error("校验客户端RedirectUri失败,ClientID=" + oauthRequest.getClientId());
+                OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
+                        .setError(OAuthError.TokenResponse.INVALID_CLIENT)
+                        .setErrorDescription(OauthConstants.INVALID_CLIENT_REDIRECTURI)
+                        .buildBodyMessage();
+                return new ResponseEntity<>(response.getBody(), headers, HttpStatus.valueOf(response.getResponseStatus()));
+            }
+            // 校验客户端grant_type
+            String[] grantTypes = client.getGrantTypes().split(",");
+            boolean grantTypeFlag = false;
+            for (String grantType : grantTypes) {
+                if (grantType.equalsIgnoreCase(oauthRequest.getResponseType())) {
+                    grantTypeFlag = true;
+                }
+            }
+            if (!grantTypeFlag) {
+                log.error("校验客户端grantType失败,ClientID=" + oauthRequest.getClientId());
+                OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
+                        .setError(OAuthError.TokenResponse.INVALID_CLIENT)
+                        .setErrorDescription(OauthConstants.INVALID_CLIENT_GRANT_TYPES)
+                        .buildBodyMessage();
+                return new ResponseEntity<>(response.getBody(), headers, HttpStatus.valueOf(response.getResponseStatus()));
+            }
+            Subject subject = SecurityUtils.getSubject();
+            // 如果用户没有登录,跳转登录页面
+            if (!subject.isAuthenticated()) {
+                if (!login(subject, request, client.getClientId())) { // 登录失败
+                    model.addAttribute("client", client);
+                    return "oauth2login";
+                }
+            }
+            //String username = ((SysUser) subject.getPrincipal()).getUserName();
+            JWTToken jwtToken = (JWTToken) subject.getPrincipal();
+            String username = jwtToken.getUsername();
+            // 生成授权码
+            String authorizationCode = null;
+            // resopnseType 目前仅支持CODE, 另外还有TOKEN
+            String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
+            if (responseType.equals(ResponseType.CODE.toString())) {
+                OAuthIssuerImpl oAuthIssuer = new OAuthIssuerImpl(new MD5Generator());
+                authorizationCode = oAuthIssuer.authorizationCode();
+                log.info("服务端生成的授权码=" + authorizationCode);
+                AuthCode code = new AuthCode();
+                code.setClientId(client.getClientId());
+                code.setCode(authorizationCode);
+                code.setCreateDate(new Date());
+                code.setUserId(username);
+                authCodeService.save(code);
+            }
+            // 构建OAuth响应
+            OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
+            // 设置授权码
+            builder.setCode(authorizationCode);
+            // 得到 到客户端请求地址中的redirect_uri重定向地址
+            String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
+            // 构建响应
+            OAuthResponse response = builder.location(redirectURI).buildQueryMessage();
+            // 根据OAuthResponse返回ResponseEntity响应
+            headers.setLocation(new URI(response.getLocationUri()));
+            return new ResponseEntity<>(headers, HttpStatus.valueOf(response.getResponseStatus()));
+        } catch (OAuthProblemException e) {
+            // 处理出错
+            String redirectUri = e.getRedirectUri();
+            if (OAuthUtils.isEmpty(redirectUri)) {
+                // 告诉客户端没有传入回调地址
+                return new ResponseEntity<>("OAuth callback url needs to be provider by client!!", HttpStatus.NOT_FOUND);
+            }
+            // 返回消息错误(如?error=)
+            OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_FOUND).error(e).location(redirectUri).buildQueryMessage();
+            headers.setLocation(new URI(response.getLocationUri()));
+            return new ResponseEntity<>(headers, HttpStatus.valueOf(response.getResponseStatus()));
+        }
+
+    }
+
+    private boolean login(Subject subject, HttpServletRequest request, String clientId) {
+        if ("get".equalsIgnoreCase(request.getMethod())) {
+            return false;
+        }
+        String username = request.getParameter("username");
+        String ftyId = request.getParameter("ftyId");
+        String ftyCode = request.getParameter("ftycode");
+        String lang = request.getParameter("lang");
+        if (StringUtils.isEmpty(username)) {
+            return false;
+        }
+        //UsernamePasswordToken token = new UsernamePasswordToken(username, password);
+        String token = JwtUtil.sign(username, ftyId, ftyCode, clientId, username,lang);
+        //JwtToken jwtToken = new JwtToken(token);
+        JWTToken jwtToken = JWTToken.build(token, username, ftyId, ftyCode, username, OauthConstants.EXPIRES_IN, GrantType.AUTHORIZATION_CODE.toString(), null,lang);
+        try {
+            //token.setRememberMe(true);
+            subject.login(jwtToken);
+            return true;
+        } catch (Exception e) {
+            log.error("登录异常e={}", e);
+            request.setAttribute("error", "登录失败:" + e.getClass().getName());
+            return false;
+        }
+    }
+}

+ 66 - 0
src/main/java/com/dk/oauth/controller/oauth/LogoutController.java

@@ -0,0 +1,66 @@
+package com.dk.oauth.controller.oauth;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.infrastructure.enums.ErrorCodeEnum;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.entity.AuthAccessToken;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import com.dk.oauth.util.AESSecurityUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@Controller
+public class LogoutController {
+    @Resource
+    private IAuthAccessTokenService tokenService;
+    @Value("${aes-key}")
+    private String AESKey;
+
+    /**
+     * 注销token
+     * @param request
+     * @return
+     * @throws OAuthSystemException
+     * @throws OAuthProblemException
+     */
+    @GetMapping(value = "/authorize/logout")
+    public ResponseResultVO logout(HttpServletRequest request) throws OAuthSystemException, OAuthProblemException {
+        // 注销用户
+        Subject subject = SecurityUtils.getSubject();
+        subject.logout();
+        // 构建 OAuth2 资源请求
+        OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request);
+        // 获取Access Token
+        String accessToken = oauthRequest.getAccessToken();
+        try {
+            accessToken = AESSecurityUtil.decrypt(AESKey, accessToken);
+        } catch (Exception e) {
+            log.error("解密Token失败,{}", e.getMessage());
+        }
+        // 获取Access Token
+        AuthAccessToken token = tokenService.getOne(new QueryWrapper<AuthAccessToken>().lambda().eq(AuthAccessToken::getTokenId, accessToken));
+        if (null == token) {
+            log.info("toke is null");
+            return ResponseResultUtil.error(ErrorCodeEnum.USER_TOKEN_EXPIRE.getCode(), OauthConstants.INVALID_TOKEN_NOTFOUND);
+        }
+        // 设置token过期分钟数为0
+        token.setTokenExpiredSeconds(0L);
+        tokenService.update(token, new QueryWrapper<AuthAccessToken>().lambda().eq(AuthAccessToken::getTokenId, token.getTokenId()));
+        // 返回结果
+        return ResponseResultUtil.success(token);
+    }
+
+}

+ 96 - 0
src/main/java/com/dk/oauth/controller/oauth/UserInfoController.java

@@ -0,0 +1,96 @@
+package com.dk.oauth.controller.oauth;
+
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.common.service.UserService;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@RestController
+public class UserInfoController {
+
+    @Resource
+    private IAuthAccessTokenService tokenService;
+    @Resource
+    private UserService userService;
+    @Value("${aes-key}")
+    private String AESKey;
+
+
+    /**
+     * 客户端根据code可获取user信息,这里只返回username
+     */
+    @GetMapping(value = "/getUser")
+    public ResponseResultVO userInfo(HttpServletRequest request) throws OAuthSystemException {
+        try {
+//            System.out.println("--->>> SecurityUtils.getSubject().getPrincipal()" + SecurityUtils.getSubject().getPrincipal());
+//            System.out.println("SecurityUtils.getSubject().isAuthenticated() = " + SecurityUtils.getSubject().isAuthenticated());
+//            // 解析token
+//            String decryptToken = JwtUtil.getDecryptToken(request, AESKey);
+//            String userNameForToken = JwtUtil.getUserName(decryptToken);
+//            String userIdForToken = JwtUtil.getUserId(decryptToken);
+//            String companyIdForToken = JwtUtil.getCompanyId(decryptToken);
+//            String grantTypeForToken = JwtUtil.getGrantType(decryptToken);
+//
+//            // 构建 OAuth2 资源请求
+//            OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request);
+//            // 获取Access Token
+//            String accessToken = oauthRequest.getAccessToken();
+//            accessToken = AESSecurityUtil.decrypt(AESKey, accessToken);
+//            // 验证Access Token
+//            AuthAccessToken token = tokenService.getOne(new QueryWrapper<AuthAccessToken>().lambda().eq(AuthAccessToken::getTokenId, accessToken));
+//            long expiredTime = token.getCreateDate().getTime() + token.getTokenExpiredSeconds();
+//            long currentTime = System.currentTimeMillis();
+//            if (expiredTime < currentTime) {
+//                log.info("accessToken 已过期  accessToken=" + accessToken);
+//                // 不存在(过期),则返回未验证,需重新验证
+//                return ResponseResultUtil.error(ErrorCodeEnum.USER_TOKEN_EXPIRE.getCode(), ErrorCodeEnum.USER_TOKEN_EXPIRE.getMessage());
+//            }
+//            // 返回用户名
+//            String username = token.getUserId();
+//            String companyId = token.getCompanyId();
+//            UserVO resultVo = new UserVO();
+//            // 查询用户信息
+//            UserVO selectVo = new UserVO();
+//            // 用户编码为登录名
+//            selectVo.setUserCode(username);
+//            ResponseResultVO<PageList<UserVO>> selectResponse = userService.selectByCond(selectVo);
+//            if (selectResponse != null && selectResponse.getData() != null && CollectionUtils.isNotEmpty(selectResponse.getData().getList())) {
+//                resultVo = selectResponse.getData().getList().get(0);
+//            }
+//            return ResponseResultUtil.success(resultVo);
+//        } catch (OAuthProblemException e) {
+//            // 检查是否设置了错误码
+//            String errorCode = e.getError();
+//            if (OAuthUtils.isEmpty(errorCode)) {
+//                return ResponseResultUtil.error(HttpServletResponse.SC_UNAUTHORIZED, OauthConstants.RESOURCE_SERVER_NAME);
+//            }
+//
+//            OAuthResponse oauthResponse = OAuthRSResponse
+//                    .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
+//                    .setRealm(OauthConstants.RESOURCE_SERVER_NAME)
+//                    .setError(e.getError())
+//                    .setErrorDescription(e.getDescription())
+//                    .setErrorUri(e.getUri())
+//                    .buildHeaderMessage();
+//            HttpHeaders headers = new HttpHeaders();
+//            headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,
+//                    oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
+//            return ResponseResultUtil.error(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase());
+            return null;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return ResponseResultUtil.error(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase());
+    }
+
+}

+ 64 - 0
src/main/java/com/dk/oauth/dto/AuthAccessTokenDto.java

@@ -0,0 +1,64 @@
+package com.dk.oauth.dto;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * (AuthAccessToken)DTO类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:04
+ */
+@Data
+@Accessors(chain = true)
+public class AuthAccessTokenDto implements Serializable {
+    private static final long serialVersionUID = 371120747704947903L;
+    //分页对象
+    private Page page;
+    /**
+     * ID列表
+     */
+    private List<Long> ids;
+
+
+    private String id;
+
+    private String clientId;
+
+    private String tokenId;
+
+    private Long tokenExpiredSeconds;
+
+    private String authenticationId;
+
+    private String userId;
+
+    private String ftyId;
+
+    private String tokenType;
+
+    private String refreshToken;
+
+    private Integer refreshTokenExpiredSeconds;
+
+    private Date createDate;
+
+    private String creater;
+
+    private String lastUpdateBy;
+
+    private Date lastUpdateDate;
+
+    //1 企业微信  2 小程序
+    private Integer wxType;
+
+    private String code;
+
+    private String agentId;
+    
+}

+ 65 - 0
src/main/java/com/dk/oauth/dto/AuthClientDto.java

@@ -0,0 +1,65 @@
+package com.dk.oauth.dto;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * (AuthClient)DTO类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+public class AuthClientDto implements Serializable {
+    private static final long serialVersionUID = 720916632800119292L;
+    // 0 启用 1 禁用
+    public static final short STATE_0 = 0;
+    public static final short STATE_1 = 1;
+
+    //分页对象
+    private Page page;
+    /**
+     * ID列表
+     */
+    private List<Long> ids;
+
+    private String id;
+
+    private String clientName;
+
+    private String clientId;
+
+    private String clientSecret;
+
+    private String clientUri;
+
+    private String clientIconUri;
+
+    private String resourceIds;
+
+    private String scope;
+
+    private String grantTypes;
+
+    private String redirectUri;
+
+    private Short state;
+
+    private String description;
+
+    private String creater;
+
+    private Date createDate;
+
+    private String createOrg;
+
+    private String lastUpdateBy;
+
+    private Date lastUpdateDate;
+}

+ 52 - 0
src/main/java/com/dk/oauth/dto/AuthCodeDto.java

@@ -0,0 +1,52 @@
+package com.dk.oauth.dto;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * (AuthCode)DTO类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+public class AuthCodeDto implements Serializable {
+    private static final long serialVersionUID = 489451318098568543L;
+    //分页对象
+    private Page page;
+    /**
+     * ID列表
+     */
+    private List<Long> ids;
+
+
+    private String code;
+
+    private String userId;
+
+    private String clientId;
+    /**
+     * 创建时间
+     */
+    private Date createDate;
+
+    private Integer state;
+    /**
+     * 创建人
+     */
+    private String creater;
+    /**
+     * 最后更新人
+     */
+    private String lastUpdateBy;
+    /**
+     * 最后更新时间
+     */
+    private Date lastUpdateDate;
+}

+ 66 - 0
src/main/java/com/dk/oauth/dto/AuthUserLoginLogDto.java

@@ -0,0 +1,66 @@
+package com.dk.oauth.dto;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * (AuthUserLoginLog)DTO类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+public class AuthUserLoginLogDto implements Serializable {
+    private static final long serialVersionUID = -36535745574417101L;
+    //分页对象
+    private Page page;
+    /**
+     * ID列表
+     */
+    private List<Long> ids;
+
+
+    private String id;
+
+    private String userId;
+    /**
+     * 登陆方式(登录方式 第三方/邮箱/手机等)
+     */
+    private Short loginType;
+    /**
+     * 操作类型 1登陆成功  2登出成功 3登录失败 4登出失败
+     */
+    private Short command;
+
+    private String version;
+
+    private String client;
+
+    private String deviceId;
+
+    private String lastIp;
+    /**
+     * 登陆系统(windows/linux/ios/android)
+     */
+    private String loginOs;
+    /**
+     * 系统版本
+     */
+    private String osver;
+
+    private String creater;
+
+    private Date createDate;
+
+    private String createOrg;
+
+    private String lastUpdateBy;
+
+    private Date lastUpdateDate;
+}

+ 73 - 0
src/main/java/com/dk/oauth/entity/AuthAccessToken.java

@@ -0,0 +1,73 @@
+package com.dk.oauth.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * (AuthAccessToken)实体类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:03
+ */
+@Data
+@Accessors(chain = true)
+@TableName(value = "auth_access_token",schema="core")
+@ApiModel(value = "auth_access_token对象", description = "${tableInfo.comment}")
+public class AuthAccessToken {
+    private static final long serialVersionUID = 609728602009854139L;
+
+
+    @TableId(type = IdType.AUTO)
+    @TableField("id")
+    private String id;
+
+    @TableField("client_id")
+    private String clientId;
+
+    @TableField("token_id")
+    private String tokenId;
+
+    @TableField("token_expired_seconds")
+    private Long tokenExpiredSeconds;
+
+    @TableField("authentication_id")
+    private String authenticationId;
+
+    @TableField("user_id")
+    private String userId;
+
+    @TableField("fty_id")
+    private String ftyId;
+
+    @TableField("fty_code")
+    private String ftyCode;
+
+    @TableField("token_type")
+    private String tokenType;
+
+    @TableField("refresh_token")
+    private String refreshToken;
+
+    @TableField("refresh_token_expired_seconds")
+    private Integer refreshTokenExpiredSeconds;
+
+    @TableField("create_date")
+    private Date createDate;
+
+    @TableField("creater")
+    private String creater;
+
+    @TableField("last_update_by")
+    private String lastUpdateBy;
+
+    @TableField("last_update_date")
+    private Date lastUpdateDate;
+
+}

+ 79 - 0
src/main/java/com/dk/oauth/entity/AuthClient.java

@@ -0,0 +1,79 @@
+package com.dk.oauth.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * (AuthClient)实体类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+@TableName(value = "auth_client",schema="core")
+@ApiModel(value = "auth_client对象", description = "${tableInfo.comment}")
+public class AuthClient implements Serializable {
+    private static final long serialVersionUID = 797527324359363898L;
+
+
+    @TableId(type = IdType.ASSIGN_UUID)
+    private String id;
+
+    @TableField("client_name")
+    private String clientName;
+
+    @TableField("client_id")
+    private String clientId;
+
+    @TableField("client_secret")
+    private String clientSecret;
+
+    @TableField("client_uri")
+    private String clientUri;
+
+    @TableField("client_icon_uri")
+    private String clientIconUri;
+
+    @TableField("resource_ids")
+    private String resourceIds;
+
+    @TableField("scope")
+    private String scope;
+
+    @TableField("grant_types")
+    private String grantTypes;
+
+    @TableField("redirect_uri")
+    private String redirectUri;
+
+    @TableField("state")
+    private Short state;
+
+    @TableField("description")
+    private String description;
+
+    @TableField("creater")
+    private String creater;
+
+    @TableField("create_date")
+    private Date createDate;
+
+    @TableField("create_org")
+    private String createOrg;
+
+    @TableField("last_update_by")
+    private String lastUpdateBy;
+
+    @TableField("last_update_date")
+    private Date lastUpdateDate;
+
+}

+ 68 - 0
src/main/java/com/dk/oauth/entity/AuthCode.java

@@ -0,0 +1,68 @@
+package com.dk.oauth.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * (AuthCode)实体类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+@TableName(value = "auth_code",schema="core")
+@ApiModel(value = "auth_code对象", description = "${tableInfo.comment}")
+public class AuthCode {
+    private static final long serialVersionUID = 530532860710429881L;
+
+    //0:正常,1:被锁定
+    public static final short STATE_1 = 1;
+    public static final short STATE_0 = 0;
+
+    @TableId(type = IdType.AUTO)
+    @TableField("code")
+    private String code;
+
+    @TableField("user_id")
+    private String userId;
+
+    @TableField("client_id")
+    private String clientId;
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty(value = "创建时间")
+    @TableField("create_date")
+    private Date createDate;
+
+    @TableField("state")
+    private Integer state;
+    /**
+     * 创建人
+     */
+    @ApiModelProperty(value = "创建人")
+    @TableField("creater")
+    private String creater;
+    /**
+     * 最后更新人
+     */
+    @ApiModelProperty(value = "最后更新人")
+    @TableField("last_update_by")
+    private String lastUpdateBy;
+    /**
+     * 最后更新时间
+     */
+    @ApiModelProperty(value = "最后更新时间")
+    @TableField("last_update_date")
+    private Date lastUpdateDate;
+
+}

+ 96 - 0
src/main/java/com/dk/oauth/entity/AuthUserLoginLog.java

@@ -0,0 +1,96 @@
+package com.dk.oauth.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * (AuthUserLoginLog)实体类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Data
+@Accessors(chain = true)
+@TableName(value = "auth_user_login_log",schema="core")
+@ApiModel(value = "auth_user_login_log对象", description = "${tableInfo.comment}")
+public class AuthUserLoginLog {
+    private static final long serialVersionUID = -92351792239110203L;
+
+    // 0.第三方 1. 邮箱 2.手机 3.密码
+    public static final Short LOGIN_TYPE0 = 0;
+    public static final Short LOGIN_TYPE1 = 1;
+    public static final Short LOGIN_TYPE2 = 2;
+    public static final Short LOGIN_TYPE3 = 3;
+    // 操作类型 1登陆成功  2登出成功 3登录失败 4登出失败
+    public static final Short LOGIN_COMMAND1 = 1;
+    public static final Short LOGIN_COMMAND2 = 2;
+    public static final Short LOGIN_COMMAND3 = 3;
+    public static final Short LOGIN_COMMAND4 = 4;
+
+    @TableId(type = IdType.AUTO)
+    @TableField("id")
+    private String id;
+
+    @TableField("user_id")
+    private String userId;
+    /**
+     * 登陆方式(登录方式 第三方/邮箱/手机等)
+     */
+    @ApiModelProperty(value = "登陆方式(登录方式 第三方/邮箱/手机等)")
+    @TableField("login_type")
+    private Short loginType;
+    /**
+     * 操作类型 1登陆成功  2登出成功 3登录失败 4登出失败
+     */
+    @ApiModelProperty(value = "操作类型 1登陆成功  2登出成功 3登录失败 4登出失败")
+    @TableField("command")
+    private Short command;
+
+    @TableField("version")
+    private String version;
+
+    @TableField("client")
+    private String client;
+
+    @TableField("device_id")
+    private String deviceId;
+
+    @TableField("last_ip")
+    private String lastIp;
+    /**
+     * 登陆系统(windows/linux/ios/android)
+     */
+    @ApiModelProperty(value = "登陆系统(windows/linux/ios/android)")
+    @TableField("login_os")
+    private String loginOs;
+    /**
+     * 系统版本
+     */
+    @ApiModelProperty(value = "系统版本")
+    @TableField("osver")
+    private String osver;
+
+    @TableField("creater")
+    private String creater;
+
+    @TableField("create_date")
+    private Date createDate;
+
+    @TableField("create_org")
+    private String createOrg;
+
+    @TableField("last_update_by")
+    private String lastUpdateBy;
+
+    @TableField("last_update_date")
+    private Date lastUpdateDate;
+
+}

+ 20 - 0
src/main/java/com/dk/oauth/feign/service/UserFeignService.java

@@ -0,0 +1,20 @@
+package com.dk.oauth.feign.service;
+
+import com.dk.common.model.pojo.PageList;
+import com.dk.common.model.vo.core.UserVO;
+import com.dk.common.response.ResponseResultVO;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * @Author: dapeng
+ * @Description:
+ * @Date: create in 2022/7/1 15:23
+ */
+//@FeignClient(name = Constant.USER_PREFIX + Constant.SERVER , path = Constant.USER, fallback = UserFeignServiceImpl.class)
+public interface UserFeignService {
+
+    @PostMapping("{list_by}")
+    ResponseResultVO<PageList<UserVO>> selectByCond(@RequestBody UserVO userVo);
+
+}

+ 22 - 0
src/main/java/com/dk/oauth/feign/service/impl/UserFeignServiceImpl.java

@@ -0,0 +1,22 @@
+package com.dk.oauth.feign.service.impl;
+
+import com.dk.common.model.pojo.PageList;
+import com.dk.common.model.vo.core.UserVO;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.feign.service.UserFeignService;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Author: dapeng
+ * @Description:
+ * @Date: create in 2022/7/1 15:24
+ */
+@Slf4j
+//@Component
+public class UserFeignServiceImpl implements UserFeignService {
+    @Override
+    public ResponseResultVO<PageList<UserVO>> selectByCond(UserVO userVo) {
+        log.error("sorry,UserService feign selectByCond error!");
+        return null;
+    }
+}

+ 26 - 0
src/main/java/com/dk/oauth/mapper/AuthAccessTokenMapper.java

@@ -0,0 +1,26 @@
+package com.dk.oauth.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dk.oauth.dto.AuthAccessTokenDto;
+import com.dk.oauth.entity.AuthAccessToken;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * (AuthAccessToken)表数据库访问层
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:04
+ */
+public interface AuthAccessTokenMapper extends BaseMapper<AuthAccessToken> {
+
+    IPage<AuthAccessTokenDto> pageQuery(Page page, @Param("authAccessTokenDto") AuthAccessTokenDto authAccessTokenDto);
+
+    /**
+     * @desc   : 查询用户最新token
+     * @author : 洪旭东
+     * @date   : 2022-08-02 17:30
+     */
+    String getCurrentToken(@Param("userId") Long userId);
+}

+ 20 - 0
src/main/java/com/dk/oauth/mapper/AuthClientMapper.java

@@ -0,0 +1,20 @@
+package com.dk.oauth.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dk.oauth.dto.AuthClientDto;
+import com.dk.oauth.entity.AuthClient;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * (AuthClient)表数据库访问层
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface AuthClientMapper extends BaseMapper<AuthClient> {
+
+    IPage<AuthClientDto> pageQuery(Page page, @Param("authClientDto") AuthClientDto authClientDto);
+
+}

+ 20 - 0
src/main/java/com/dk/oauth/mapper/AuthCodeMapper.java

@@ -0,0 +1,20 @@
+package com.dk.oauth.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dk.oauth.dto.AuthCodeDto;
+import com.dk.oauth.entity.AuthCode;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * (AuthCode)表数据库访问层
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface AuthCodeMapper extends BaseMapper<AuthCode> {
+
+    IPage<AuthCodeDto> pageQuery(Page page, @Param("authCodeDto") AuthCodeDto authCodeDto);
+
+}

+ 20 - 0
src/main/java/com/dk/oauth/mapper/AuthUserLoginLogMapper.java

@@ -0,0 +1,20 @@
+package com.dk.oauth.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dk.oauth.dto.AuthUserLoginLogDto;
+import com.dk.oauth.entity.AuthUserLoginLog;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * (AuthUserLoginLog)表数据库访问层
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface AuthUserLoginLogMapper extends BaseMapper<AuthUserLoginLog> {
+
+    IPage<AuthUserLoginLogDto> pageQuery(Page page, @Param("authUserLoginLogDto") AuthUserLoginLogDto authUserLoginLogDto);
+
+}

+ 19 - 0
src/main/java/com/dk/oauth/service/IAuthAccessTokenService.java

@@ -0,0 +1,19 @@
+package com.dk.oauth.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthAccessTokenDto;
+import com.dk.oauth.entity.AuthAccessToken;
+
+/**
+ * (AuthAccessToken)表服务接口
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:05
+ */
+public interface IAuthAccessTokenService extends IService<AuthAccessToken> {
+
+    ResponseResultVO pageQuery(AuthAccessTokenDto authAccessTokenDto);
+
+    String getCurrentToken(Long userId);
+}

+ 17 - 0
src/main/java/com/dk/oauth/service/IAuthClientService.java

@@ -0,0 +1,17 @@
+package com.dk.oauth.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthClientDto;
+import com.dk.oauth.entity.AuthClient;
+
+/**
+ * (AuthClient)表服务接口
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface IAuthClientService extends IService<AuthClient> {
+
+    ResponseResultVO pageQuery(AuthClientDto authClientDto);
+}

+ 17 - 0
src/main/java/com/dk/oauth/service/IAuthCodeService.java

@@ -0,0 +1,17 @@
+package com.dk.oauth.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthCodeDto;
+import com.dk.oauth.entity.AuthCode;
+
+/**
+ * (AuthCode)表服务接口
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface IAuthCodeService extends IService<AuthCode> {
+
+    ResponseResultVO pageQuery(AuthCodeDto authCodeDto);
+}

+ 17 - 0
src/main/java/com/dk/oauth/service/IAuthUserLoginLogService.java

@@ -0,0 +1,17 @@
+package com.dk.oauth.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthUserLoginLogDto;
+import com.dk.oauth.entity.AuthUserLoginLog;
+
+/**
+ * (AuthUserLoginLog)表服务接口
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+public interface IAuthUserLoginLogService extends IService<AuthUserLoginLog> {
+
+    ResponseResultVO pageQuery(AuthUserLoginLogDto authUserLoginLogDto);
+}

+ 52 - 0
src/main/java/com/dk/oauth/service/impl/AuthAccessTokenServiceImpl.java

@@ -0,0 +1,52 @@
+package com.dk.oauth.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthAccessTokenDto;
+import com.dk.oauth.entity.AuthAccessToken;
+import com.dk.oauth.mapper.AuthAccessTokenMapper;
+import com.dk.oauth.service.IAuthAccessTokenService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * (AuthAccessToken)表服务实现类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:05
+ */
+@Service("authAccessTokenService")
+public class AuthAccessTokenServiceImpl extends ServiceImpl<AuthAccessTokenMapper, AuthAccessToken> implements IAuthAccessTokenService {
+
+    @Resource
+    private AuthAccessTokenMapper authAccessTokenMapper;
+
+    /**
+     * 分页查询
+     *
+     * @param
+     * @return
+     */
+    @Override
+    public ResponseResultVO pageQuery(AuthAccessTokenDto authAccessTokenDto) {
+        if (null == authAccessTokenDto.getPage()) {
+            authAccessTokenDto.setPage(new Page(0, 10));
+        }
+        IPage<AuthAccessTokenDto> authAccessTokenDtos = authAccessTokenMapper.pageQuery(authAccessTokenDto.getPage(), authAccessTokenDto);
+        return ResponseResultUtil.success(authAccessTokenDtos);
+    }
+
+
+    /**
+     * @desc   : 查询用户最新token
+     * @author : 洪旭东
+     * @date   : 2022-08-02 17:30
+     */
+    public String getCurrentToken(Long userId){
+        return authAccessTokenMapper.getCurrentToken(userId);
+    }
+}

+ 43 - 0
src/main/java/com/dk/oauth/service/impl/AuthClientServiceImpl.java

@@ -0,0 +1,43 @@
+package com.dk.oauth.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthClientDto;
+import com.dk.oauth.entity.AuthClient;
+import com.dk.oauth.mapper.AuthClientMapper;
+import com.dk.oauth.service.IAuthClientService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * (AuthClient)表服务实现类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Service("authClientService")
+public class AuthClientServiceImpl extends ServiceImpl<AuthClientMapper, AuthClient> implements IAuthClientService {
+
+    @Resource
+    private AuthClientMapper authClientMapper;
+
+    /**
+     * 分页查询
+     *
+     * @param
+     * @return
+     */
+    @Override
+    public ResponseResultVO pageQuery(AuthClientDto authClientDto) {
+        if (null == authClientDto.getPage()) {
+            authClientDto.setPage(new Page(0, 10));
+        }
+        IPage<AuthClientDto> authClientDtos = authClientMapper.pageQuery(authClientDto.getPage(), authClientDto);
+        return ResponseResultUtil.success(authClientDtos);
+    }
+
+}

+ 44 - 0
src/main/java/com/dk/oauth/service/impl/AuthCodeServiceImpl.java

@@ -0,0 +1,44 @@
+package com.dk.oauth.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthCodeDto;
+import com.dk.oauth.entity.AuthCode;
+import com.dk.oauth.mapper.AuthCodeMapper;
+import com.dk.oauth.service.IAuthCodeService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+
+/**
+ * (AuthCode)表服务实现类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Service("authCodeService")
+public class AuthCodeServiceImpl extends ServiceImpl<AuthCodeMapper, AuthCode> implements IAuthCodeService {
+
+    @Resource
+    private AuthCodeMapper authCodeMapper;
+
+    /**
+     * 分页查询
+     *
+     * @param
+     * @return
+     */
+    @Override
+    public ResponseResultVO pageQuery(AuthCodeDto authCodeDto) {
+        if (null == authCodeDto.getPage()) {
+            authCodeDto.setPage(new Page(0, 10));
+        }
+        IPage<AuthCodeDto> authCodeDtos = authCodeMapper.pageQuery(authCodeDto.getPage(), authCodeDto);
+        return ResponseResultUtil.success(authCodeDtos);
+    }
+
+}

+ 43 - 0
src/main/java/com/dk/oauth/service/impl/AuthUserLoginLogServiceImpl.java

@@ -0,0 +1,43 @@
+package com.dk.oauth.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dk.common.response.ResponseResultUtil;
+import com.dk.common.response.ResponseResultVO;
+import com.dk.oauth.dto.AuthUserLoginLogDto;
+import com.dk.oauth.entity.AuthUserLoginLog;
+import com.dk.oauth.mapper.AuthUserLoginLogMapper;
+import com.dk.oauth.service.IAuthUserLoginLogService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * (AuthUserLoginLog)表服务实现类
+ *
+ * @author dapeng
+ * @since 2022-07-01 09:41:06
+ */
+@Service("authUserLoginLogService")
+public class AuthUserLoginLogServiceImpl extends ServiceImpl<AuthUserLoginLogMapper, AuthUserLoginLog> implements IAuthUserLoginLogService {
+
+    @Resource
+    private AuthUserLoginLogMapper authUserLoginLogMapper;
+
+    /**
+     * 分页查询
+     *
+     * @param
+     * @return
+     */
+    @Override
+    public ResponseResultVO pageQuery(AuthUserLoginLogDto authUserLoginLogDto) {
+        if (null == authUserLoginLogDto.getPage()) {
+            authUserLoginLogDto.setPage(new Page(0, 10));
+        }
+        IPage<AuthUserLoginLogDto> authUserLoginLogDtos = authUserLoginLogMapper.pageQuery(authUserLoginLogDto.getPage(), authUserLoginLogDto);
+        return ResponseResultUtil.success(authUserLoginLogDtos);
+    }
+
+}

+ 26 - 0
src/main/java/com/dk/oauth/shiro/credentials/JWTCredentialsMatcher.java

@@ -0,0 +1,26 @@
+package com.dk.oauth.shiro.credentials;
+
+import com.dk.oauth.util.JwtUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.credential.CredentialsMatcher;
+
+/**
+ * JWT证书匹配
+ */
+@Slf4j
+public class JWTCredentialsMatcher implements CredentialsMatcher {
+
+    @Override
+    public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
+        String token = authenticationToken.getCredentials().toString();
+        String salt = authenticationInfo.getCredentials().toString();
+        try {
+            return JwtUtil.verify(token, salt);
+        } catch (Exception e) {
+            log.error("JWT Token CredentialsMatch Exception:" + e.getMessage(), e);
+        }
+        return false;
+    }
+}

+ 86 - 0
src/main/java/com/dk/oauth/shiro/filter/OAuth2AuthenticationFilter.java

@@ -0,0 +1,86 @@
+package com.dk.oauth.shiro.filter;
+
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.shiro.jwt.JWTToken;
+import com.dk.oauth.util.JwtUtil;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.rs.extractor.BearerHeaderTokenExtractor;
+import org.apache.oltu.oauth2.rs.extractor.TokenExtractor;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 该 filter 的作用类似于 FormAuthenticationFilter 用于 oauth2 客户端的身份验证控制
+ */
+@Data
+@Slf4j
+public class OAuth2AuthenticationFilter extends AuthenticatingFilter {
+    // oauth2 authc code参数名
+    private String authcCodeParam;
+    // 客户端id
+    private String clientId;
+    // 服务器端登录成功/失败后重定向到的客户端地址
+    private String redirectUrl;
+    // oauth2服务器响应类型
+    private String responseType;
+    private String failureUrl;
+    private TokenExtractor extractor = new BearerHeaderTokenExtractor();
+
+    @Override
+    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
+        return null;
+    }
+
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+        return false;
+    }
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        HttpServletRequest httpRequest = (HttpServletRequest) request;
+        Subject subject = getSubject(httpRequest, response);
+        // 判断是否登陆
+        log.info("--->>> subject.isAuthenticated() == " + subject.isAuthenticated());
+        if (!subject.isAuthenticated()) {
+            String accessToken = this.extractor.getAccessToken(httpRequest);
+            if (StringUtils.isEmpty(request.getParameter(authcCodeParam)) && StringUtils.isEmpty(accessToken)) {
+                // 如果没有身份认证,且没有authCode,则重定向到服务端授权
+                saveRequestAndRedirectToLogin(request, response);
+            } else {
+                // 登陆处理,不走shiro自带的登陆方法
+                String userName = JwtUtil.getUserName(accessToken);
+                String ftyId = JwtUtil.getFtyId(accessToken);
+                String ftyCode = JwtUtil.getFtyCode(accessToken);
+                JWTToken jwtToken = JWTToken.build(accessToken, userName, ftyId, ftyCode, userName, OauthConstants.EXPIRES_IN, GrantType.AUTHORIZATION_CODE.toString(), clientId, request.getParameter("lang"));
+                WebUtils.saveRequest(request);
+                SecurityUtils.getSubject().login(jwtToken);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
+        return false;
+    }
+
+    @Override
+    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
+        WebUtils.issueRedirect(request, response, getSuccessUrl());
+        // 表示执行链结束
+        return false;
+    }
+}

+ 33 - 0
src/main/java/com/dk/oauth/shiro/jwt/JWTGenerator.java

@@ -0,0 +1,33 @@
+package com.dk.oauth.shiro.jwt;
+
+import com.dk.oauth.util.JwtUtil;
+import lombok.Data;
+import org.apache.oltu.oauth2.as.issuer.ValueGenerator;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+
+@Data
+public class JWTGenerator implements ValueGenerator {
+
+    private String username;
+    private String userId;
+    private String ftyId;
+    private String ftyCode;
+    private String clientId;
+    private String salt;
+    private String grantType;
+    private String appCode;
+    private String lang;
+
+    @Override
+    public String generateValue() throws OAuthSystemException {
+        System.out.println("--->>> generateValue()");
+        return JwtUtil.sign(username, userId, appCode, clientId, salt, ftyId, ftyCode, lang);
+    }
+
+    @Override
+    public String generateValue(String param) throws OAuthSystemException {
+        System.out.println("--->>> generateValuegenerateValue(String param)");
+        return JwtUtil.sign(username, userId, appCode, clientId, salt, ftyId, ftyCode, lang);
+    }
+
+}

+ 102 - 0
src/main/java/com/dk/oauth/shiro/jwt/JWTToken.java

@@ -0,0 +1,102 @@
+package com.dk.oauth.shiro.jwt;
+
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.dk.oauth.util.JwtUtil;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.shiro.authc.AuthenticationToken;
+
+import java.util.Date;
+
+@Data
+@Accessors(chain = true)
+public class JWTToken implements AuthenticationToken {
+
+    private static final long serialVersionUID = -8451637096112402805L;
+
+    /**
+     * 登陆模式
+     */
+    private String grantType;
+
+    private String clientId;
+
+    private String clientSecret;
+
+    /**
+     * 登录ip
+     */
+    private String host;
+    /**
+     * 登录用户名称
+     */
+    private String username;
+    /**
+     * 工厂Id
+     */
+    private String ftyId;
+    /**
+     * 工厂编码
+     */
+    private String ftyCode;
+    /**
+     * 登录盐值
+     */
+    private String salt;
+    /**
+     * 登录token
+     */
+    private String token;
+    /**
+     * 创建时间
+     */
+    private Date createDate;
+    /**
+     * 多长时间过期,默认一小时
+     */
+    private long expireSecond;
+    /**
+     * 过期日期
+     */
+    private Date expireDate;
+
+    private String principal;
+
+    private String credentials;
+    private String lang;
+
+    @Override
+    public Object getPrincipal() {
+        return token;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return token;
+    }
+
+    public static JWTToken build(String token, String username, String ftyId, String ftyCode, String salt, long expireSecond, String grantType, String clientId, String lang) {
+        DecodedJWT decodedJwt = JwtUtil.getJwtInfo(token);
+        Date createDate = decodedJwt.getIssuedAt();
+        Date expireDate = decodedJwt.getExpiresAt();
+        if (StringUtils.isEmpty(grantType)) {
+            grantType = GrantType.AUTHORIZATION_CODE.toString();
+        }
+        return new JWTToken()
+                .setUsername(username)
+                .setFtyId(ftyId)
+                .setFtyCode(ftyCode)
+                .setToken(token)
+                .setHost("127.0.0.1")
+                .setSalt(salt)
+                .setCreateDate(createDate)
+                .setExpireSecond(expireSecond)
+                .setExpireDate(expireDate)
+                .setGrantType(grantType)
+                .setClientId(clientId)
+                .setLang(lang);
+    }
+
+}

+ 15 - 0
src/main/java/com/dk/oauth/shiro/realm/CustomeRealm.java

@@ -0,0 +1,15 @@
+package com.dk.oauth.shiro.realm;
+
+/**
+ * 接口
+ */
+public interface CustomeRealm {
+
+    /**
+     * 获取授权类型
+     *
+     * @return
+     */
+    public String getGrantType();
+
+}

+ 95 - 0
src/main/java/com/dk/oauth/shiro/realm/JWTClientRealm.java

@@ -0,0 +1,95 @@
+package com.dk.oauth.shiro.realm;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.entity.AuthClient;
+import com.dk.oauth.service.IAuthClientService;
+import com.dk.oauth.shiro.jwt.JWTToken;
+import com.dk.oauth.util.JwtUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ObjectUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Slf4j
+public class JWTClientRealm extends AuthorizingRealm implements CustomeRealm {
+
+    @Autowired
+    private IAuthClientService authClientService;
+
+    @Override
+    public String getGrantType() {
+        return GrantType.CLIENT_CREDENTIALS.toString();
+    }
+
+    /**
+     * 必须重写此方法,不然Shiro会报错
+     */
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JWTToken;
+    }
+
+    /**
+     * 访问控制。客户端默认角色为client,只能访问角色控制为client的函数
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+        log.info("--->>> JWT REALM doGetAuthorizationInfo");
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        JWTToken token = (JWTToken) principalCollection.getPrimaryPrincipal();
+        if (token == null) {
+            log.error("授权失败,用户信息为空!!!");
+            return null;
+        }
+        try {
+            //客户端无角色与权限
+            Set<String> roleList = new HashSet<>();
+            roleList.add("client");
+            Set<String> permissionList = new HashSet<>();
+            simpleAuthorizationInfo.setRoles(roleList);
+            simpleAuthorizationInfo.setStringPermissions(permissionList);
+        } catch (Exception e) {
+            log.error("授权失败,请检查系统内部错误!!!", e);
+        }
+        return simpleAuthorizationInfo;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+        log.info("--->>> JWT JWTClientRealm doGetAuthenticationInfo");
+        // 校验token
+        JWTToken jwtToken = (JWTToken) authenticationToken;
+        if (ObjectUtils.isEmpty(jwtToken)) {
+            throw new AuthenticationException("json web token is null");
+        }
+        AuthClient client = authClientService.getOne(new QueryWrapper<AuthClient>().lambda().eq(AuthClient::getClientId, jwtToken.getClientId()));
+        String userName = JwtUtil.getUserName(jwtToken.getToken());
+        String ftyId = JwtUtil.getFtyId(jwtToken.getToken());
+        String ftyCode = JwtUtil.getFtyCode(jwtToken.getToken());
+        String lang = JwtUtil.getLang(jwtToken.getToken());
+        log.info("----------------->>>>>");
+        String token = "";
+        JWTToken buildToken = null;
+        if ("微信".equals(client.getClientName())) {
+            token = JwtUtil.sign(userName, ftyId, ftyCode, client.getClientId(), userName,lang);
+            buildToken = JWTToken.build(token, userName, ftyId, ftyCode, userName, OauthConstants.EXPIRES_IN, GrantType.CLIENT_CREDENTIALS.toString(), client.getClientId(), lang);
+            return new SimpleAuthenticationInfo(buildToken, userName, getName());
+        } else {
+            token = JwtUtil.sign(userName, ftyId, ftyCode, client.getClientId(), client.getClientSecret(),lang);
+            buildToken = JWTToken.build(token, client.getClientId(), ftyId, ftyCode, client.getClientId(), OauthConstants.EXPIRES_IN, GrantType.CLIENT_CREDENTIALS.toString(), client.getClientId(), lang);
+            return new SimpleAuthenticationInfo(buildToken, client.getClientId(), getName());
+        }
+    }
+}

+ 52 - 0
src/main/java/com/dk/oauth/shiro/realm/JWTModularRealmAuthenticator.java

@@ -0,0 +1,52 @@
+package com.dk.oauth.shiro.realm;
+
+import com.dk.oauth.shiro.jwt.JWTToken;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
+import org.apache.shiro.realm.Realm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 当配置了多个Realm时,我们通常使用的认证器是shiro自带的org.apache.shiro.authc.pam.ModularRealmAuthenticator,其中决定使用的Realm的是doAuthenticate()方法
+ * <p>
+ * 自定义Authenticator,通过grantType进行判断
+ */
+@Slf4j
+public class JWTModularRealmAuthenticator extends ModularRealmAuthenticator {
+    @Override
+    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
+            throws AuthenticationException {
+        log.info("JWTModularRealmAuthenticator:method doAuthenticate() execute ");
+        // 判断getRealms()是否返回为空
+        assertRealmsConfigured();
+        // 强制转换回自定义的CustomizedToken
+        //UserToken userToken = (UserToken) authenticationToken;
+        JWTToken jwtToken = (JWTToken) authenticationToken;
+        // 登录类型
+        String grantType = jwtToken.getGrantType();
+        // 所有Realm
+        Collection<Realm> realms = getRealms();
+        // 登录类型对应的所有Realm
+        List<Realm> typeRealms = new ArrayList<>();
+        for (Realm realm : realms) {
+            CustomeRealm customeRealm = (CustomeRealm) realm;
+            if (customeRealm.getGrantType().contains(grantType)) {
+                typeRealms.add(realm);
+            }
+        }
+        // 判断是单Realm还是多Realm
+        if (typeRealms.size() == 1) {
+            log.info("doSingleRealmAuthentication() execute ");
+            return doSingleRealmAuthentication(typeRealms.get(0), jwtToken);
+        } else {
+            log.info("doMultiRealmAuthentication() execute ");
+            return doMultiRealmAuthentication(typeRealms, jwtToken);
+        }
+    }
+}

+ 105 - 0
src/main/java/com/dk/oauth/shiro/realm/JWTRealm.java

@@ -0,0 +1,105 @@
+package com.dk.oauth.shiro.realm;
+
+import com.dk.common.service.UserService;
+import com.dk.common.infrastructure.constant.OauthConstants;
+import com.dk.oauth.shiro.jwt.JWTToken;
+import com.dk.oauth.util.JwtUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ObjectUtils;
+
+@Slf4j
+public class JWTRealm extends AuthorizingRealm implements CustomeRealm {
+
+    @Autowired
+    private UserService userService;
+
+
+    @Override
+    public String getGrantType() {
+        return GrantType.AUTHORIZATION_CODE.toString() + "," + GrantType.PASSWORD.toString();
+    }
+
+    /**
+     * 必须重写此方法,不然Shiro会报错
+     */
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof JWTToken;
+    }
+
+    /**
+     * 访问控制。
+     *
+     * @param principalCollection
+     * @return
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+        log.info("--->>> JWT REALM doGetAuthorizationInfo");
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        JWTToken token = (JWTToken) principalCollection.getPrimaryPrincipal();
+        if (token == null) {
+            log.error("授权失败,用户信息为空!!!");
+            return null;
+        }
+        try {
+            /*ResponseData userRes = userService.queryByName(token.getUsername());
+            IapSysUserTDto userDto = (IapSysUserTDto) userRes.getData();
+            List<IapSysRoleTDto> roles = userDto.getIapSysRoleTDtoList();
+            Set<String> roleList = new HashSet<>();
+            Set<String> permissionList = new HashSet<>();
+            for (IapSysRoleTDto role : roles) {
+                roleList.add(role.getRoleCode());
+                for (IapSysAuthTDto auth : role.getAuths()) {
+                    permissionList.add(auth.getAuthName());
+                }
+            }
+            simpleAuthorizationInfo.setRoles(roleList);
+            simpleAuthorizationInfo.setStringPermissions(permissionList);*/
+        } catch (Exception e) {
+            log.error("授权失败,请检查系统内部错误!!!", e);
+        }
+        return simpleAuthorizationInfo;
+    }
+
+    /**
+     * 用户身份识别(登录")
+     *
+     * @param authenticationToken
+     * @return
+     * @throws AuthenticationException
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+        log.info("--->>> JWT REALM doGetAuthenticationInfo");
+        // 校验token
+        JWTToken jwtToken = (JWTToken) authenticationToken;
+        if (ObjectUtils.isEmpty(jwtToken)) {
+            throw new AuthenticationException("json web token is null");
+        }
+        String salt = jwtToken.getSalt();
+        if (StringUtils.isBlank(salt)) {
+            throw new AuthenticationException("salt is null");
+        }
+        String userName = jwtToken.getUsername();
+        String ftyId = jwtToken.getFtyId();
+        String ftyCode = jwtToken.getFtyCode();
+        String lang = jwtToken.getLang();
+        String token = JwtUtil.sign(userName, ftyId, ftyCode, jwtToken.getClientId(), userName,lang);
+        // SALT字段需要替换
+        JWTToken buildToken = JWTToken.build(token, userName, ftyId, ftyCode, salt, OauthConstants.EXPIRES_IN, GrantType.AUTHORIZATION_CODE.toString(), null,lang);
+        return new SimpleAuthenticationInfo(buildToken, salt, getName());
+    }
+
+}

+ 9 - 0
src/main/java/com/dk/oauth/shiro/test/TestUserPassword.java

@@ -0,0 +1,9 @@
+package com.dk.oauth.shiro.test;
+
+public class TestUserPassword {
+
+    public static void main(String[] args) {
+        System.out.println("");
+    }
+
+}

+ 69 - 0
src/main/java/com/dk/oauth/util/AESSecurityUtil.java

@@ -0,0 +1,69 @@
+package com.dk.oauth.util;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Key;
+import java.util.Base64;
+import java.util.UUID;
+
+/**
+ * AES加密算法工具
+ */
+public class AESSecurityUtil {
+
+    /**
+     * 指定加密算法为AES
+     */
+    private static final String ALGORITHM = "AES";
+
+    /**
+     * 用来进行加密的操作
+     *
+     * @param data
+     * @return
+     * @throws Exception
+     */
+    public static String encrypt(String keyString, String data)
+            throws Exception {
+        Key key = generateKey(keyString);
+        Cipher c = Cipher.getInstance(ALGORITHM);
+        c.init(Cipher.ENCRYPT_MODE, key);
+        byte[] encVal = c.doFinal(data.getBytes());
+        String encryptedValue = Base64.getEncoder().encodeToString(encVal);
+        return encryptedValue;
+    }
+
+    /**
+     * 用来进行解密的操作
+     *
+     * @param encryptedData
+     * @return
+     * @throws Exception
+     */
+    public static String decrypt(String keyString, String encryptedData) throws Exception {
+        Key key = generateKey(keyString);
+        Cipher c = Cipher.getInstance(ALGORITHM);
+        c.init(Cipher.DECRYPT_MODE, key);
+        byte[] decordedValue = Base64.getDecoder().decode(encryptedData);
+        byte[] decValue = c.doFinal(decordedValue);
+        String decryptedValue = new String(decValue);
+        return decryptedValue;
+    }
+
+    public static String generateKeyString() {
+        //必须长度为16
+        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
+    }
+
+    /**
+     * 根据密钥和算法生成Key
+     *
+     * @return
+     * @throws Exception
+     */
+    private static Key generateKey(String keyString) throws Exception {
+        Key key = new SecretKeySpec(keyString.getBytes(), ALGORITHM);
+        return key;
+    }
+
+}

+ 194 - 0
src/main/java/com/dk/oauth/util/DateUtil.java

@@ -0,0 +1,194 @@
+package com.dk.oauth.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * 时间工具
+ */
+public class DateUtil {
+
+    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+
+    public static Date now() {
+        return new Date();
+    }
+
+    public static String date(long timestamp) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return sdf.format(new Date(timestamp));
+    }
+
+    /**
+     * 日期类型转字符串
+     *
+     * @param date
+     * @return
+     */
+    public static String dateToString(Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return sdf.format(date);
+    }
+
+    /**
+     * 日期类型转字符串     template自己需要的格式
+     *
+     * @param date
+     * @return
+     */
+    public static String dateToString(Date date,String template ) {
+        SimpleDateFormat sdf = new SimpleDateFormat(template);
+        return sdf.format(date);
+    }
+
+    /**
+     * 日期类型转字符串(转化为yyyyMMdd格式)
+     *
+     * @param date
+     * @return
+     */
+    public static String dateToYYYYMMdd(Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+        return sdf.format(date);
+    }
+
+    /**
+     * 日期类型转字符串(转化为yyyyMM格式)
+     *
+     * @param date
+     * @return
+     */
+    public static String dateToYYYYMM(Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
+        return sdf.format(date);
+    }
+
+    /**
+     * 日期类型转字符串(转化为yyyy格式)
+     *
+     * @param date
+     * @return
+     */
+    public static String dateToYYYY(Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
+        return sdf.format(date);
+    }
+
+    /**
+     * 日期格式转化
+     *
+     * @param date
+     * @param format
+     * @return
+     */
+    public static String dateFormat(Date date, String format) {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        return sdf.format(date);
+    }
+
+    /**
+     * 2017-01-01  得到  01/01/2017
+     * @param date
+     * @return
+     */
+    public  static String strReverse(String date){
+        String[] split = date.split("-");
+        StringBuilder stringBuilder=new StringBuilder();
+        stringBuilder.append(split[1]).append("/").append(split[2]).append("/").append(split[0]);
+        return stringBuilder.toString();
+    }
+
+
+    /**
+     * 01/01/2017  得到  2017-01-01
+     * @param date
+     * @return
+     * @throws ParseException
+     */
+    public  static Date getHGDateConvert(String date) throws ParseException {
+        String[] split = date.split("/");
+        StringBuilder stringBuilder=new StringBuilder();
+        stringBuilder.append(split[2]).append("-").append(split[1]).append("-").append(split[0]);
+        Date parse = simpleDateFormat.parse(stringBuilder.toString());
+        return  parse;
+    }
+
+    /**
+     * 格式化日期为字符串
+     *
+     * @param date date
+     * @return 日期字符串   2017-01-01
+     */
+    public static String format(Date date){
+        Instant instant = date.toInstant();
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+        return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+    }
+
+    /**
+     * 日期格式转化   使用 Thu Jun 18 11:11:49 GMT+08:00 2020
+     * @param
+     * @param format
+     * @return
+     */
+    public static Date stringConvertDate(String format) throws ParseException {
+
+        Date date= new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyy", Locale.US).parse(format);
+        return  date;
+
+    }
+
+    /**
+     * 日期格式转化  07/02/2020 10:08:43
+     * @param
+     * @param format
+     * @return
+     */
+    public static Date stringConvertDateTwo(String format) throws ParseException {
+
+        Date date= new SimpleDateFormat("dd/MM/YYYY HH:mm:ss", Locale.US).parse(format);
+        return  date;
+
+
+    }
+
+    /**
+     * 获取day天之后的日期
+     * @param day 天数
+     * @return
+     */
+    public static Date getAddDayDate(int day){
+        Calendar calendar1 = Calendar.getInstance();
+        calendar1.add(Calendar.DATE, day);
+        return calendar1.getTime();
+    }
+
+    /**
+     * 获得指定日期的后一天
+     * @param specifiedDay
+     * @return
+     */
+    public static String getSpecifiedDayAfter(String specifiedDay){
+        Calendar c = Calendar.getInstance();
+        Date date=null;
+        try {
+            date = new SimpleDateFormat("yyyy-MM-dd").parse(specifiedDay);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        c.setTime(date);
+        int day=c.get(Calendar.DATE);
+        c.set(Calendar.DATE,day+1);
+
+        String dayAfter=new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
+        return dayAfter;
+    }
+
+}

+ 135 - 0
src/main/java/com/dk/oauth/util/IpUtil.java

@@ -0,0 +1,135 @@
+package com.dk.oauth.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class IpUtil {
+    private static String pattern = "^Mozilla/\\d\\.\\d\\s+\\(+.+?\\)";
+    private static String pattern2 = "\\(+.+?\\)";
+    private static Pattern r = Pattern.compile(pattern);
+    private static Pattern r2 = Pattern.compile(pattern2);
+
+    /**
+     * 获取登录用户的IP地址
+     *
+     * @param request
+     * @return
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
+        String ip = request.getHeader("X-Forwarded-For");
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("Proxy-Client-IP");
+            }
+            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("WL-Proxy-Client-IP");
+            }
+            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_CLIENT_IP");
+            }
+            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+            }
+            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getRemoteAddr();
+            }
+        } else if (ip.length() > 15) {
+            String[] ips = ip.split(",");
+            for (int index = 0; index < ips.length; index++) {
+                String strIp = (String) ips[index];
+                if (!("unknown".equalsIgnoreCase(strIp))) {
+                    ip = strIp;
+                    break;
+                }
+            }
+        }
+        return ip;
+    }
+
+    /**
+     * 获取浏览器信息
+     *
+     * @param userAgent
+     * @return
+     */
+    public static String getBrowser(String userAgent) {
+        String browser = "";
+        String version = "";
+        Integer startLen = 0;
+        Integer endLen = 0;
+        if (userAgent.toLowerCase().indexOf("msie") != -1) {
+            browser = "IE";
+            startLen = userAgent.toLowerCase().indexOf("msie");
+            endLen = userAgent.indexOf(";", startLen);
+            version = userAgent.substring(startLen + 5, endLen);
+        } else if (userAgent.toLowerCase().indexOf("trident/7") != -1) {
+            browser = "IE";
+            startLen = userAgent.toLowerCase().indexOf("rv:") + 3;
+            endLen = userAgent.indexOf(")", startLen);
+            version = userAgent.substring(startLen, endLen);
+        } else if (userAgent.toLowerCase().indexOf("chrome") != -1) {
+            browser = "CHROME";
+            startLen = userAgent.toLowerCase().indexOf("chrome") + 7;
+            endLen = userAgent.indexOf(" ", startLen);
+            version = userAgent.substring(startLen, endLen);
+        } else if (userAgent.toLowerCase().indexOf("firefox") != -1) {
+            browser = "FIREFOX";
+            startLen = userAgent.toLowerCase().indexOf("firefox") + 8;
+            endLen = userAgent.length();
+            version = userAgent.substring(startLen, endLen);
+        } else if (userAgent.toLowerCase().indexOf("safari") != -1) {
+            browser = "SAFARI";
+            startLen = userAgent.toLowerCase().indexOf("version") + 8;
+            endLen = userAgent.indexOf(" ", startLen);
+            version = userAgent.substring(startLen, endLen);
+        } else if (userAgent.toLowerCase().indexOf("opera") != -1) {
+            browser = "OPERA";
+            startLen = userAgent.toLowerCase().indexOf("opera") + 6;
+            endLen = userAgent.length();
+            version = userAgent.substring(startLen, endLen);
+        } else {
+            browser = "OTHER";
+        }
+        return browser + "_" + version;
+    }
+
+    /**
+     * 获得操作系统信息
+     *
+     * @return
+     */
+    public static String getDeviceInfo(HttpServletRequest request) {
+        String userAgent = request.getHeader("User-Agent");
+        return getDeviceInfo(userAgent);
+    }
+
+    private static String getDeviceInfo(String userAgent) {
+        Matcher m = r.matcher(userAgent);
+        String result = null;
+        if (m.find()) {
+            result = m.group(0);
+        }
+
+        Matcher m2 = r2.matcher(result);
+        if (m2.find()) {
+            result = m2.group(0);
+        }
+        result = result.replace("(", "");
+        result = result.replace(")", "");
+        return filterDeviceInfo(result);
+    }
+
+    public static String filterDeviceInfo(String result) {
+        if (StringUtils.isEmpty(result)) {
+            return null;
+        }
+        result = result.replace(" U;", "");
+        result = result.replace(" zh-cn;", "");
+        return result;
+    }
+}

+ 273 - 0
src/main/java/com/dk/oauth/util/JwtUtil.java

@@ -0,0 +1,273 @@
+package com.dk.oauth.util;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.dk.common.infrastructure.constant.OauthConstants;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+
+@Slf4j
+public class JwtUtil {
+    public static final String SHIRO_USER_NAME = "username";
+    public static final String SHIRO_USER_ID = "userId";
+    public static final String SHIRO_FTY_ID = "ftyId";
+    public static final String SHIRO_FTY_CODE = "ftyCode";
+    public static final String SHIRO_CLIENT_ID = "clientId";
+    public static final String SHIRO_APP_CODE = "appCode";
+    public static final String SHIRO_USER_SALT = "salt";
+    public static final String SHIRO_ISSUER = "Issuer";
+    public static final String SHIRO_SUBJECT = "long_token";
+    public static final String SHIRO_GRANT_TYPE = "grantType";
+    public static final String SHIRO_APP_LANG = "lang";
+
+    /**
+     * 校验token是否正确
+     *
+     * @param token 密钥
+     * @param salt  盐值
+     * @return 是否正确
+     */
+    public static boolean verify(String token, String salt) {
+        try {
+            Algorithm algorithm = Algorithm.HMAC256(salt);
+            JWTVerifier verifier = JWT.require(algorithm)
+                    // 签发人
+                    .withIssuer(SHIRO_ISSUER)
+                    // 主题
+                    .withSubject(SHIRO_SUBJECT)
+                    // 签发的目标
+                    //.withAudience(jwtProperties.getAudience())
+                    .build();
+            DecodedJWT jwt = verifier.verify(token);
+            if (jwt != null) {
+                return true;
+            }
+        } catch (Exception e) {
+            log.error("The token is invalid{}", e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 获取AES解密token
+     *
+     * @param request
+     * @return
+     */
+    public static String getDecryptToken(HttpServletRequest request, String AESKey) {
+        String token = "";
+        try {
+            // 构建 OAuth2 资源请求
+            OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request);
+            // 获取Access Token
+            String accessToken = oauthRequest.getAccessToken();
+            token = AESSecurityUtil.decrypt(AESKey, accessToken);
+            return token;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @desc : 获取token中UserName
+     * @author : 周兴
+     * @date : 2023/2/26 16:32
+     */
+    public static String getUserName(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_USER_NAME).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * @desc : 获取token中UserId
+     * @author : 周兴
+     * @date : 2023/2/26 16:32
+     */
+    public static String getUserId(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_USER_ID).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * @desc : 获取token中FtyId
+     * @author : 周兴
+     * @date : 2023/2/26 16:32
+     */
+    public static String getFtyId(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_FTY_ID).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * @desc : 获取token中FtyCode
+     * @author : 周兴
+     * @date : 2023/2/26 16:32
+     */
+    public static String getFtyCode(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_FTY_CODE).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * @desc : 获取token中Lang
+     * @author : 周兴
+     * @date : 2023/2/26 16:32
+     */
+    public static String getLang(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_APP_LANG).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    public static String getGrantType(String token) {
+        try {
+            DecodedJWT jwt = JWT.decode(token);
+            return jwt.getClaim(SHIRO_GRANT_TYPE).asString();
+        } catch (JWTDecodeException e) {
+            log.error("error:{}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 解析token,获取token数据
+     *
+     * @param token
+     * @return
+     */
+    public static DecodedJWT getJwtInfo(String token) {
+        return JWT.decode(token);
+    }
+
+    /**
+     * 生成TOKEN,24小时后过期
+     *
+     * @param username 用户名
+     * @param salt     盐值
+     * @return 加密的token
+     */
+    public static String sign(String username, String userId, String appCode, String clientId, String salt, String ftyId, String ftyCode, String lang) {
+        Date expireDate = new Date(System.currentTimeMillis() + OauthConstants.EXPIRES_IN);
+        //加盐值
+        Algorithm algorithm = Algorithm.HMAC256(salt);
+        // 附带username信息
+        return JWT.create()
+                .withClaim(SHIRO_USER_NAME, username)
+                .withClaim(SHIRO_USER_ID, userId)
+                .withClaim(SHIRO_FTY_ID, ftyId)
+                .withClaim(SHIRO_FTY_CODE, ftyCode)
+                .withClaim(SHIRO_APP_CODE, appCode)
+                .withClaim(SHIRO_CLIENT_ID, clientId)
+                .withClaim(SHIRO_USER_SALT, salt)
+                .withClaim(SHIRO_APP_LANG, lang)
+                // jwt唯一id
+                .withJWTId(uuid32())
+                // 签发人
+                .withIssuer(SHIRO_ISSUER)
+                // 主题
+                .withSubject(SHIRO_SUBJECT)
+                // 签发的目标
+                //.withAudience(jwtProperties.getAudience())
+                // 签名时间
+                .withIssuedAt(new Date())
+                // token过期时间
+                .withExpiresAt(expireDate)
+                // 签名
+                .sign(algorithm);
+    }
+
+    public static String sign(String username, String userId, String appCode, String clientId, String salt, String grantType, String ftyId, String ftyCode, String lang) {
+        Date expireDate = new Date(System.currentTimeMillis() + OauthConstants.EXPIRES_IN);
+        //加盐值
+        Algorithm algorithm = Algorithm.HMAC256(salt);
+        // 附带username信息
+        return JWT.create()
+                .withClaim(SHIRO_USER_NAME, username)
+                .withClaim(SHIRO_USER_ID, userId)
+                .withClaim(SHIRO_FTY_ID, ftyId)
+                .withClaim(SHIRO_FTY_CODE, ftyCode)
+                .withClaim(SHIRO_APP_CODE, appCode)
+                .withClaim(SHIRO_CLIENT_ID, clientId)
+                .withClaim(SHIRO_USER_SALT, salt)
+                .withClaim(SHIRO_GRANT_TYPE, grantType)
+                .withClaim(SHIRO_APP_LANG, lang)
+                // jwt唯一id
+                .withJWTId(uuid32())
+                // 签发人
+                .withIssuer(SHIRO_ISSUER)
+                // 主题
+                .withSubject(SHIRO_SUBJECT)
+                // 签发的目标
+                //.withAudience(jwtProperties.getAudience())
+                // 签名时间
+                .withIssuedAt(new Date())
+                // token过期时间
+                .withExpiresAt(expireDate)
+                // 签名
+                .sign(algorithm);
+    }
+
+    public static String sign(String username, String clientId, String salt, String ftyId, String ftyCode, String lang) {
+        Date expireDate = new Date(System.currentTimeMillis() + OauthConstants.EXPIRES_IN);
+        //加盐值
+        Algorithm algorithm = Algorithm.HMAC256(salt);
+        // 附带username信息
+        return JWT.create()
+                .withClaim(SHIRO_USER_NAME, username)
+                .withClaim(SHIRO_FTY_ID, ftyId)
+                .withClaim(SHIRO_FTY_CODE, ftyCode)
+                .withClaim(SHIRO_CLIENT_ID, clientId)
+                .withClaim(SHIRO_USER_SALT, salt)
+                .withClaim(SHIRO_APP_LANG, lang)
+                // jwt唯一id
+                .withJWTId(uuid32())
+                // 签发人
+                .withIssuer(SHIRO_ISSUER)
+                // 主题
+                .withSubject(SHIRO_SUBJECT)
+                // 签发的目标
+                //.withAudience(jwtProperties.getAudience())
+                // 签名时间
+                .withIssuedAt(new Date())
+                // token过期时间
+                .withExpiresAt(expireDate)
+                // 签名
+                .sign(algorithm);
+    }
+
+    public static String uuid32() {
+        return java.util.UUID.randomUUID().toString().replace("-", "");
+    }
+
+
+}

+ 45 - 0
src/main/java/com/dk/oauth/util/PassWordUtil.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dk.oauth.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 密码加密工具类
+ */
+@Slf4j
+public class PassWordUtil {
+
+    /**
+     * 密码加盐,再加密
+     *
+     * @param pwd
+     * @param salt
+     * @return
+     */
+    public static String encrypt(String pwd, String salt) {
+        if (StringUtils.isBlank(pwd)) {
+            throw new IllegalArgumentException("密码不能为空");
+        }
+        if (StringUtils.isBlank(salt)) {
+            throw new IllegalArgumentException("盐值不能为空");
+        }
+        return DigestUtils.sha256Hex(pwd + salt);
+    }
+
+}

+ 38 - 0
src/main/java/com/dk/oauth/util/SaltUtil.java

@@ -0,0 +1,38 @@
+package com.dk.oauth.util;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.crypto.SecureRandomNumberGenerator;
+
+/**
+ * 盐值包装工具类
+ */
+public class SaltUtil {
+
+    /**
+     * 盐值包装
+     *
+     * @param secret 配置文件中配置的附加盐值
+     * @param salt   数据库中保存的盐值
+     * @return
+     */
+    public static String getSalt(String secret, String salt) {
+        if (StringUtils.isBlank(secret) && StringUtils.isBlank(salt)) {
+            return null;
+        }
+        // 加密方法
+        String newSalt = DigestUtils.sha256Hex(secret + salt);
+        return newSalt;
+    }
+
+    /**
+     * 生成32位随机盐
+     *
+     * @return
+     */
+    public static String generateSalt() {
+        return new SecureRandomNumberGenerator().nextBytes(16).toHex();
+    }
+
+}
+

+ 54 - 0
src/main/java/com/dk/oauth/util/UUID.java

@@ -0,0 +1,54 @@
+package com.dk.oauth.util;
+
+import java.util.Random;
+
+/**
+ * 随机guid生成
+ */
+public class UUID {
+
+    public static String uuid32 () {
+        return java.util.UUID.randomUUID().toString().replace("-", "");
+    }
+
+    /**
+     * 获取16位随机字符串
+     * @return String
+     */
+    public static String getUUID16() {
+        String uuid= UUID.uuid32().toString();
+        char[] cs=new char[32];
+        char c=0;
+        for(int i=uuid.length()/2,j=1;i-->0;){
+            if((c=uuid.charAt(i))!='-'){
+                cs[j++]=c;
+            }
+        }
+        String uid=String.valueOf(cs);
+        return uid;
+    }
+
+
+    /**
+     * 获取随机数
+     * @param length
+     * @return
+     * @throws NumberFormatException
+     */
+    public static String getRandomString(int length) throws NumberFormatException{
+        // 定义一个字符串(A-Z,a-z,0-9)即62位;
+        String str="zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
+        //由Random生成随机数
+        Random random=new Random();
+        StringBuffer sb=new StringBuffer();
+        //长度为几就循环几次
+        for(int i=0; i<length; ++i){
+            //产生0-61的数字
+            int number=random.nextInt(62);
+            //将产生的数字通过length次承载到sb中
+            sb.append(str.charAt(number));
+        }
+        //将承载的字符转换成字符串
+        return sb.toString();
+    }
+}

+ 115 - 0
src/main/resources/dev/bootstrap.yml

@@ -0,0 +1,115 @@
+server:
+  port: 7002
+spring:
+  application:
+    name: oauth-server
+  cloud:
+    nacos:
+      config:
+        server-addr: 124.71.26.125:8848
+      discovery:
+        server-addr: 124.71.26.125:8848
+        namespace: iboss-dev
+  datasource:
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://s.dev01.dkiboss.com:15000/dkmes3
+    username: mes_dev
+    password: dk
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      initial-size: 10 # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
+      max-active: 150 # 最大连接池连接数量,最大活跃连接数
+      min-idle: 10 # 最小连接池连接数量,最小空闲数量
+      max-wait: 300000   # 获取连接时最大等待时间,单位毫秒
+      # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
+      pool-prepared-statements: false
+      # 指定每个连接上PSCache的大小
+      # max-pool-prepared-statement-per-connection-size: 20
+      # 和上面的等价
+      # max-open-prepared-statements:
+      # 指定检测连接sql,如果是null,会影响testWhileIdle、testOnBorrow、testOnReturn失效,如果底层代码use-ping-method是true,默认使用ping
+      validation-query: SELECT 1
+      validation-query-timeout: 500
+      # 申请连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接
+      test-on-borrow: false
+      # 归还连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接,放回数据库线程池
+      test-on-return: false
+      # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果此连接空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
+      test-while-idle: true
+      # 1)配合testWhileIdle=true时使用,如果当前jdbc使用间隔大于timeBetweenEvictionRunsMillis配置的空闲连接过期时间,执行validationQuery检测连接是否有效。
+      # 数据库会主动超时并断开连接,因此建议timeBetweenEvictionRunsMillis小于数据库的连接主动断开时间(如mysql的wait_timeout和interactive_timeout)
+      # 2)配置间隔多久才进行一次检测,Destroy线程检测需要关闭的空闲连接的时间,单位是毫秒
+      time-between-eviction-runs-millis: 55000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      min-evictable-idle-time-millis: 30000
+      # max-evictable-idle-time-millis:
+      # 通过connectProperties属性来打开mergeSql功能;记录慢SQL
+      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+      filters: slf4j #sql文不允许写#注释,只可以在xml中写 <!--  -->注释
+      stat-view-servlet:
+        enabled: true
+        login-username: dongke
+        login-password: dongke
+        url-pattern: /druid/*
+        reset-enable: false
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.css,/druid/*"
+  redis:
+    host: s.dev01.dkiboss.com
+    port: 14000
+    password: dk
+  zipkin:
+    base-url: http://s.dev01.dkiboss.com:9411/
+    discovery-client-enabled: false
+    sleuth:
+      sampler:
+        probability: 1
+
+logback:
+  file: D:\data\DK_MES\${spring.application.name}
+
+feign:
+  sentinel:
+    enabled: true
+  client:
+    config:
+      default:
+        connectTimeout: 60000
+        readTimeout: 60000
+
+mybatis-plus:
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+  type-aliases-package: com.dk.oauth.dto,com.dk.common.infrastructure.handler #类型转换器包名
+  mapper-locations: classpath:/mapper/**/*Mapper.xml,com/hegii/scrm/common/mapper/opinfo/*.xml
+
+mybatis:
+  config-location: classpath:mybatis-config.xml
+
+swagger:
+  enabled: true
+
+dongke:
+  base:
+    pojo:
+      valid-key: flg_valid  #db有效标识
+      is-valid: true  #表示有效的值
+      un-valid: false  #表示无效的值
+      delete-key: flg_del  #db删除标识
+      is-delete: true  #表示删除的值
+      un-delete: false  #表示未删除的值
+    dynamic-ds:
+      ds-key: DS
+    ds:
+      table-name:
+
+#  单点登录是否开启
+single-sign-on: false
+uploadPath: ''
+printTemplatePath : ''
+excel-folder: D:\data\DK_MES\excel\
+
+aes-key: b6f64c1001b04b9f
+client-app-id: 48849faf-8bbb-4a29-9548-0ba1c3df963f
+

+ 191 - 0
src/main/resources/logback-spring.xml

@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration  scan="true" scanPeriod="10 seconds">
+
+    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
+
+    <springProperty scope="context" name="log.path" source="logback.file" defaultValue="log"/>
+    <contextName>logback</contextName>
+    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
+    <!--<property name="log.path" value="E:/logsNew" />-->
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+
+
+    <!--输出到控制台-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>info</level>
+        </filter>
+        <encoder>
+            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
+            <!-- 设置字符集 -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+
+    <!--输出到文件-->
+
+    <!-- 时间滚动输出 level为 DEBUG 日志 -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <!--<file>${log.path}/log_debug.log</file>-->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 时间滚动输出 level为 INFO 日志 -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <!--<file>${log.path}/log_info.log</file>-->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 每天日志归档路径以及格式 -->
+            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录info级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 时间滚动输出 level为 WARN 日志 -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <!--<file>${log.path}/log_warn.log</file>-->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录warn级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <!--<file>${log.path}/log_error.log</file>-->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录ERROR级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!--
+        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
+        以及指定<appender>。<logger>仅有一个name属性,
+        一个可选的level和一个可选的addtivity属性。
+        name:用来指定受此logger约束的某一个包或者具体的某一个类。
+        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
+              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
+              如果未设置此属性,那么当前logger将会继承上级的级别。
+        addtivity:是否向上级logger传递打印信息。默认是true。
+    -->
+    <logger name="org.springframework.web" level="info"/>
+    <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
+    <!-- 使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
+        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
+        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别: -->
+
+    <!-- mybatis日志打印-->
+    <!--<logger name="org.apache.ibatis" level="DEBUG" />-->
+    <!--<logger name="java.sql" level="DEBUG" />-->
+    <!--<logger name="com.dongke.hn.dao.mapper" level="DEBUG"></logger>-->
+
+
+    <!-- root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
+        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
+        不能设置为INHERITED或者同义词NULL。默认是DEBUG
+        可以包含零个或多个元素,标识这个appender将会添加到这个logger。 -->
+
+    <!--开发环境:打印控制台-->
+    <springProfile name="dev">
+        <logger name="com.sfDev.view" level="debug"/>
+    </springProfile>
+
+    <root level="info">
+        <appender-ref ref="CONSOLE" />
+        <appender-ref ref="DEBUG_FILE" />
+        <appender-ref ref="INFO_FILE" />
+        <appender-ref ref="WARN_FILE" />
+        <appender-ref ref="ERROR_FILE" />
+    </root>
+
+    <!--生产环境:输出到文件-->
+    <springProfile name="pro">
+        <root level="info">
+            <appender-ref ref="CONSOLE" />
+            <appender-ref ref="DEBUG_FILE" />
+            <appender-ref ref="INFO_FILE" />
+            <appender-ref ref="ERROR_FILE" />
+            <appender-ref ref="WARN_FILE" />
+        </root>
+    </springProfile>
+
+</configuration>

+ 80 - 0
src/main/resources/mapper/AuthAccessTokenMapper.xml

@@ -0,0 +1,80 @@
+<?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.dk.oauth.mapper.AuthAccessTokenMapper">
+
+    <resultMap type="com.dk.oauth.dto.AuthAccessTokenDto" id="AuthAccessTokenMap">
+        <result property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="clientId" column="client_id" jdbcType="VARCHAR"/>
+        <result property="tokenId" column="token_id" jdbcType="VARCHAR"/>
+        <result property="tokenExpiredSeconds" column="token_expired_seconds" jdbcType="INTEGER"/>
+        <result property="authenticationId" column="authentication_id" jdbcType="VARCHAR"/>
+        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+        <result property="ftyId" column="fty_id" jdbcType="VARCHAR"/>
+        <result property="tokenType" column="token_type" jdbcType="VARCHAR"/>
+        <result property="refreshToken" column="refresh_token" jdbcType="VARCHAR"/>
+        <result property="refreshTokenExpiredSeconds" column="refresh_token_expired_seconds" jdbcType="INTEGER"/>
+        <result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
+        <result property="creater" column="creater" jdbcType="VARCHAR"/>
+        <result property="lastUpdateBy" column="last_update_by" jdbcType="VARCHAR"/>
+        <result property="lastUpdateDate" column="last_update_date" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!--通过实体作为筛选条件查询-->
+    <select id="pageQuery" resultMap="AuthAccessTokenMap">
+        SELECT
+          id, client_id, token_id, token_expired_seconds, authentication_id, user_id, fty_id, token_type, refresh_token, refresh_token_expired_seconds, create_date, creater, last_update_by, last_update_date
+        FROM core.auth_access_token
+        <where>
+            <if test="authAccessTokenDto.id != null and authAccessTokenDto.id != ''">
+                AND id = #{authAccessTokenDto.id}
+            </if>
+            <if test="authAccessTokenDto.clientId != null and authAccessTokenDto.clientId != ''">
+                AND client_id = #{authAccessTokenDto.clientId}
+            </if>
+            <if test="authAccessTokenDto.tokenId != null and authAccessTokenDto.tokenId != ''">
+                AND token_id = #{authAccessTokenDto.tokenId}
+            </if>
+            <if test="authAccessTokenDto.tokenExpiredSeconds != null">
+                AND token_expired_seconds = #{authAccessTokenDto.tokenExpiredSeconds}
+            </if>
+            <if test="authAccessTokenDto.authenticationId != null and authAccessTokenDto.authenticationId != ''">
+                AND authentication_id = #{authAccessTokenDto.authenticationId}
+            </if>
+            <if test="authAccessTokenDto.userId != null and authAccessTokenDto.userId != ''">
+                AND user_id = #{authAccessTokenDto.userId}
+            </if>
+            <if test="authAccessTokenDto.ftyId != null and authAccessTokenDto.ftyId != ''">
+                AND fty_id = #{authAccessTokenDto.ftyId}
+            </if>
+            <if test="authAccessTokenDto.tokenType != null and authAccessTokenDto.tokenType != ''">
+                AND token_type = #{authAccessTokenDto.tokenType}
+            </if>
+            <if test="authAccessTokenDto.refreshToken != null and authAccessTokenDto.refreshToken != ''">
+                AND refresh_token = #{authAccessTokenDto.refreshToken}
+            </if>
+            <if test="authAccessTokenDto.refreshTokenExpiredSeconds != null">
+                AND refresh_token_expired_seconds = #{authAccessTokenDto.refreshTokenExpiredSeconds}
+            </if>
+            <if test="authAccessTokenDto.createDate != null">
+                AND create_date = #{authAccessTokenDto.createDate}
+            </if>
+            <if test="authAccessTokenDto.creater != null and authAccessTokenDto.creater != ''">
+                AND creater = #{authAccessTokenDto.creater}
+            </if>
+            <if test="authAccessTokenDto.lastUpdateBy != null and authAccessTokenDto.lastUpdateBy != ''">
+                AND last_update_by = #{authAccessTokenDto.lastUpdateBy}
+            </if>
+            <if test="authAccessTokenDto.lastUpdateDate != null">
+                AND last_update_date = #{authAccessTokenDto.lastUpdateDate}
+            </if>
+        </where>
+    </select>
+
+<!--    查询用户最新token-->
+    <select id="getCurrentToken" resultType="String">
+        select token_id from core.auth_access_token
+        where user_id = #{userId}::varchar and token_type = 'password'
+        order by create_date desc
+        limit 1
+    </select>
+</mapper>

+ 85 - 0
src/main/resources/mapper/AuthClientMapper.xml

@@ -0,0 +1,85 @@
+<?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.dk.oauth.mapper.AuthClientMapper">
+
+    <resultMap type="com.dk.oauth.dto.AuthClientDto" id="AuthClientMap">
+        <result property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="clientName" column="client_name" jdbcType="VARCHAR"/>
+        <result property="clientId" column="client_id" jdbcType="VARCHAR"/>
+        <result property="clientSecret" column="client_secret" jdbcType="VARCHAR"/>
+        <result property="clientUri" column="client_uri" jdbcType="VARCHAR"/>
+        <result property="clientIconUri" column="client_icon_uri" jdbcType="VARCHAR"/>
+        <result property="resourceIds" column="resource_ids" jdbcType="VARCHAR"/>
+        <result property="scope" column="scope" jdbcType="VARCHAR"/>
+        <result property="grantTypes" column="grant_types" jdbcType="VARCHAR"/>
+        <result property="redirectUri" column="redirect_uri" jdbcType="VARCHAR"/>
+        <result property="state" column="state" jdbcType="INTEGER"/>
+        <result property="description" column="description" jdbcType="VARCHAR"/>
+        <result property="creater" column="creater" jdbcType="VARCHAR"/>
+        <result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
+        <result property="createOrg" column="create_org" jdbcType="VARCHAR"/>
+        <result property="lastUpdateBy" column="last_update_by" jdbcType="VARCHAR"/>
+        <result property="lastUpdateDate" column="last_update_date" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!--通过实体作为筛选条件查询-->
+    <select id="pageQuery" resultMap="AuthClientMap">
+        SELECT
+          id, client_name, client_id, client_secret, client_uri, client_icon_uri, resource_ids, scope, grant_types, redirect_uri, state, description, creater, create_date, create_org, last_update_by, last_update_date
+        FROM core.auth_client
+        <where>
+            <if test="authClientDto.id != null and authClientDto.id != ''">
+                AND id = #{authClientDto.id}
+            </if>
+            <if test="authClientDto.clientName != null and authClientDto.clientName != ''">
+                AND client_name = #{authClientDto.clientName}
+            </if>
+            <if test="authClientDto.clientId != null and authClientDto.clientId != ''">
+                AND client_id = #{authClientDto.clientId}
+            </if>
+            <if test="authClientDto.clientSecret != null and authClientDto.clientSecret != ''">
+                AND client_secret = #{authClientDto.clientSecret}
+            </if>
+            <if test="authClientDto.clientUri != null and authClientDto.clientUri != ''">
+                AND client_uri = #{authClientDto.clientUri}
+            </if>
+            <if test="authClientDto.clientIconUri != null and authClientDto.clientIconUri != ''">
+                AND client_icon_uri = #{authClientDto.clientIconUri}
+            </if>
+            <if test="authClientDto.resourceIds != null and authClientDto.resourceIds != ''">
+                AND resource_ids = #{authClientDto.resourceIds}
+            </if>
+            <if test="authClientDto.scope != null and authClientDto.scope != ''">
+                AND scope = #{authClientDto.scope}
+            </if>
+            <if test="authClientDto.grantTypes != null and authClientDto.grantTypes != ''">
+                AND grant_types = #{authClientDto.grantTypes}
+            </if>
+            <if test="authClientDto.redirectUri != null and authClientDto.redirectUri != ''">
+                AND redirect_uri = #{authClientDto.redirectUri}
+            </if>
+            <if test="authClientDto.state != null">
+                AND state = #{authClientDto.state}
+            </if>
+            <if test="authClientDto.description != null and authClientDto.description != ''">
+                AND description = #{authClientDto.description}
+            </if>
+            <if test="authClientDto.creater != null and authClientDto.creater != ''">
+                AND creater = #{authClientDto.creater}
+            </if>
+            <if test="authClientDto.createDate != null">
+                AND create_date = #{authClientDto.createDate}
+            </if>
+            <if test="authClientDto.createOrg != null and authClientDto.createOrg != ''">
+                AND create_org = #{authClientDto.createOrg}
+            </if>
+            <if test="authClientDto.lastUpdateBy != null and authClientDto.lastUpdateBy != ''">
+                AND last_update_by = #{authClientDto.lastUpdateBy}
+            </if>
+            <if test="authClientDto.lastUpdateDate != null">
+                AND last_update_date = #{authClientDto.lastUpdateDate}
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 49 - 0
src/main/resources/mapper/AuthCodeMapper.xml

@@ -0,0 +1,49 @@
+<?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.dk.oauth.mapper.AuthCodeMapper">
+
+    <resultMap type="com.dk.oauth.dto.AuthCodeDto" id="AuthCodeMap">
+        <result property="code" column="code" jdbcType="VARCHAR"/>
+        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+        <result property="clientId" column="client_id" jdbcType="VARCHAR"/>
+        <result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
+        <result property="state" column="state" jdbcType="INTEGER"/>
+        <result property="creater" column="creater" jdbcType="VARCHAR"/>
+        <result property="lastUpdateBy" column="last_update_by" jdbcType="VARCHAR"/>
+        <result property="lastUpdateDate" column="last_update_date" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!--通过实体作为筛选条件查询-->
+    <select id="pageQuery" resultMap="AuthCodeMap">
+        SELECT
+          code, user_id, client_id, create_date, state, creater, last_update_by, last_update_date
+        FROM core.auth_code
+        <where>
+            <if test="authCodeDto.code != null and authCodeDto.code != ''">
+                AND code = #{authCodeDto.code}
+            </if>
+            <if test="authCodeDto.userId != null and authCodeDto.userId != ''">
+                AND user_id = #{authCodeDto.userId}
+            </if>
+            <if test="authCodeDto.clientId != null and authCodeDto.clientId != ''">
+                AND client_id = #{authCodeDto.clientId}
+            </if>
+            <if test="authCodeDto.createDate != null">
+                AND create_date = #{authCodeDto.createDate}
+            </if>
+            <if test="authCodeDto.state != null">
+                AND state = #{authCodeDto.state}
+            </if>
+            <if test="authCodeDto.creater != null and authCodeDto.creater != ''">
+                AND creater = #{authCodeDto.creater}
+            </if>
+            <if test="authCodeDto.lastUpdateBy != null and authCodeDto.lastUpdateBy != ''">
+                AND last_update_by = #{authCodeDto.lastUpdateBy}
+            </if>
+            <if test="authCodeDto.lastUpdateDate != null">
+                AND last_update_date = #{authCodeDto.lastUpdateDate}
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 77 - 0
src/main/resources/mapper/AuthUserLoginLogMapper.xml

@@ -0,0 +1,77 @@
+<?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.dk.oauth.mapper.AuthUserLoginLogMapper">
+
+    <resultMap type="com.dk.oauth.dto.AuthUserLoginLogDto" id="AuthUserLoginLogMap">
+        <result property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+        <result property="loginType" column="login_type" jdbcType="INTEGER"/>
+        <result property="command" column="command" jdbcType="INTEGER"/>
+        <result property="version" column="version" jdbcType="VARCHAR"/>
+        <result property="client" column="client" jdbcType="VARCHAR"/>
+        <result property="deviceId" column="device_id" jdbcType="VARCHAR"/>
+        <result property="lastIp" column="last_ip" jdbcType="VARCHAR"/>
+        <result property="loginOs" column="login_os" jdbcType="VARCHAR"/>
+        <result property="osver" column="osver" jdbcType="VARCHAR"/>
+        <result property="creater" column="creater" jdbcType="VARCHAR"/>
+        <result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
+        <result property="createOrg" column="create_org" jdbcType="VARCHAR"/>
+        <result property="lastUpdateBy" column="last_update_by" jdbcType="VARCHAR"/>
+        <result property="lastUpdateDate" column="last_update_date" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!--通过实体作为筛选条件查询-->
+    <select id="pageQuery" resultMap="AuthUserLoginLogMap">
+        SELECT
+          id, user_id, login_type, command, version, client, device_id, last_ip, login_os, osver, creater, create_date, create_org, last_update_by, last_update_date
+        FROM core.auth_user_login_log
+        <where>
+            <if test="authUserLoginLogDto.id != null and authUserLoginLogDto.id != ''">
+                AND id = #{authUserLoginLogDto.id}
+            </if>
+            <if test="authUserLoginLogDto.userId != null and authUserLoginLogDto.userId != ''">
+                AND user_id = #{authUserLoginLogDto.userId}
+            </if>
+            <if test="authUserLoginLogDto.loginType != null">
+                AND login_type = #{authUserLoginLogDto.loginType}
+            </if>
+            <if test="authUserLoginLogDto.command != null">
+                AND command = #{authUserLoginLogDto.command}
+            </if>
+            <if test="authUserLoginLogDto.version != null and authUserLoginLogDto.version != ''">
+                AND version = #{authUserLoginLogDto.version}
+            </if>
+            <if test="authUserLoginLogDto.client != null and authUserLoginLogDto.client != ''">
+                AND client = #{authUserLoginLogDto.client}
+            </if>
+            <if test="authUserLoginLogDto.deviceId != null and authUserLoginLogDto.deviceId != ''">
+                AND device_id = #{authUserLoginLogDto.deviceId}
+            </if>
+            <if test="authUserLoginLogDto.lastIp != null and authUserLoginLogDto.lastIp != ''">
+                AND last_ip = #{authUserLoginLogDto.lastIp}
+            </if>
+            <if test="authUserLoginLogDto.loginOs != null and authUserLoginLogDto.loginOs != ''">
+                AND login_os = #{authUserLoginLogDto.loginOs}
+            </if>
+            <if test="authUserLoginLogDto.osver != null and authUserLoginLogDto.osver != ''">
+                AND osver = #{authUserLoginLogDto.osver}
+            </if>
+            <if test="authUserLoginLogDto.creater != null and authUserLoginLogDto.creater != ''">
+                AND creater = #{authUserLoginLogDto.creater}
+            </if>
+            <if test="authUserLoginLogDto.createDate != null">
+                AND create_date = #{authUserLoginLogDto.createDate}
+            </if>
+            <if test="authUserLoginLogDto.createOrg != null and authUserLoginLogDto.createOrg != ''">
+                AND create_org = #{authUserLoginLogDto.createOrg}
+            </if>
+            <if test="authUserLoginLogDto.lastUpdateBy != null and authUserLoginLogDto.lastUpdateBy != ''">
+                AND last_update_by = #{authUserLoginLogDto.lastUpdateBy}
+            </if>
+            <if test="authUserLoginLogDto.lastUpdateDate != null">
+                AND last_update_date = #{authUserLoginLogDto.lastUpdateDate}
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 8 - 0
src/main/resources/mybatis-config.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+    <settings>
+        <!-- add LOG -->
+        <setting name="logImpl" value="STDOUT_LOGGING" />
+    </settings>
+</configuration>

+ 19 - 0
src/main/resources/prod/bootstrap.yml

@@ -0,0 +1,19 @@
+server:
+  port: 6008
+spring:
+  application:
+    name: oauth-server
+  cloud:
+    nacos:
+      config:
+        file-extension: yaml
+        server-addr: ${NACOS_HOST:mse-ab4cb036-nacos-ans.mse.aliyuncs.com:8848}
+        namespace: ${NACOS_SPACE:hgscrm-prod}
+        shared-configs:
+          - data-id: common.yaml
+            group: DEFAULT_GROUP
+        group: ${group-id:DEFAULT_GROUP}
+      discovery:
+        server-addr: ${NACOS_HOST:mse-ab4cb036-nacos-ans.mse.aliyuncs.com:8848}
+        namespace: ${NACOS_SPACE:hgscrm-prod}
+

+ 117 - 0
src/main/resources/st/bootstrap.yml

@@ -0,0 +1,117 @@
+server:
+  port: 6008
+spring:
+  application:
+    name: oauth-server
+  cloud:
+    nacos:
+      config:
+        server-addr: 192.168.0.90:8848
+      discovery:
+        server-addr: 192.168.0.90:8848
+        ip: 192.168.0.90 #默认是局域网ip,固定为外网ip
+        namespace: iboss-dev
+  datasource:
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://192.168.0.90:15100/dkmes3
+    username: dkmes
+    password: dk
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      initial-size: 10 # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
+      max-active: 150 # 最大连接池连接数量,最大活跃连接数
+      min-idle: 10 # 最小连接池连接数量,最小空闲数量
+      max-wait: 300000   # 获取连接时最大等待时间,单位毫秒
+      # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
+      pool-prepared-statements: false
+      # 指定每个连接上PSCache的大小
+      # max-pool-prepared-statement-per-connection-size: 20
+      # 和上面的等价
+      # max-open-prepared-statements:
+      # 指定检测连接sql,如果是null,会影响testWhileIdle、testOnBorrow、testOnReturn失效,如果底层代码use-ping-method是true,默认使用ping
+      validation-query: SELECT 1
+      validation-query-timeout: 500
+      # 申请连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接
+      test-on-borrow: false
+      # 归还连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接,放回数据库线程池
+      test-on-return: false
+      # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果此连接空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
+      test-while-idle: true
+      # 1)配合testWhileIdle=true时使用,如果当前jdbc使用间隔大于timeBetweenEvictionRunsMillis配置的空闲连接过期时间,执行validationQuery检测连接是否有效。
+      # 数据库会主动超时并断开连接,因此建议timeBetweenEvictionRunsMillis小于数据库的连接主动断开时间(如mysql的wait_timeout和interactive_timeout)
+      # 2)配置间隔多久才进行一次检测,Destroy线程检测需要关闭的空闲连接的时间,单位是毫秒
+      time-between-eviction-runs-millis: 55000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      min-evictable-idle-time-millis: 30000
+      # max-evictable-idle-time-millis:
+      # 通过connectProperties属性来打开mergeSql功能;记录慢SQL
+      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+      filters: slf4j #sql文不允许写#注释,只可以在xml中写 <!--  -->注释
+      stat-view-servlet:
+        enabled: true
+        login-username: dongke
+        login-password: dongke
+        url-pattern: /druid/*
+        reset-enable: false
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.css,/druid/*"
+  redis:
+    host: s.dev01.dkiboss.com
+    port: 14000
+    password: dk
+  zipkin:
+    base-url: http://s.dev01.dkiboss.com:9411/
+    discovery-client-enabled: false
+    sleuth:
+      sampler:
+        probability: 1
+
+logback:
+  file: /home/java_project/dk_mes/${spring.application.name}/${spring.application.name}_logs
+
+feign:
+  sentinel:
+    enabled: true
+  client:
+    config:
+      default:
+        connectTimeout: 60000
+        readTimeout: 60000
+
+mybatis-plus:
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+  type-aliases-package: com.dk.oauth.dto,com.dk.common.infrastructure.handler #类型转换器包名
+  mapper-locations: classpath:/mapper/**/*Mapper.xml,com/hegii/scrm/common/mapper/opinfo/*.xml
+
+mybatis:
+  config-location: classpath:mybatis-config.xml
+
+swagger:
+  enabled: true
+
+dongke:
+  base:
+    pojo:
+      valid-key: flg_valid  #db有效标识
+      is-valid: true  #表示有效的值
+      un-valid: false  #表示无效的值
+      delete-key: flg_del  #db删除标识
+      is-delete: true  #表示删除的值
+      un-delete: false  #表示未删除的值
+    dynamic-ds:
+      ds-key: DS
+    ds:
+      table-name:
+
+#  单点登录是否开启
+single-sign-on: false
+uploadPath: ''
+printTemplatePath : ''
+
+aes-key: b6f64c1001b04b9f
+client-app-id: 48849faf-8bbb-4a29-9548-0ba1c3df963f
+excel-folder: /home/java_project/dk_mes/mdm-server/excel/
+
+

+ 117 - 0
src/main/resources/test/bootstrap.yml

@@ -0,0 +1,117 @@
+server:
+  port: 6008
+spring:
+  application:
+    name: oauth-server
+  cloud:
+    nacos:
+      config:
+        server-addr: 124.71.26.125:8848
+      discovery:
+        server-addr: 124.71.26.125:8848
+        ip: 124.71.26.125 #默认是局域网ip,固定为外网ip
+        namespace: iboss-dev
+  datasource:
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://s.dev01.dkiboss.com:15000/dkmes3
+    username: mes_dev
+    password: dk
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      initial-size: 10 # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
+      max-active: 150 # 最大连接池连接数量,最大活跃连接数
+      min-idle: 10 # 最小连接池连接数量,最小空闲数量
+      max-wait: 300000   # 获取连接时最大等待时间,单位毫秒
+      # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
+      pool-prepared-statements: false
+      # 指定每个连接上PSCache的大小
+      # max-pool-prepared-statement-per-connection-size: 20
+      # 和上面的等价
+      # max-open-prepared-statements:
+      # 指定检测连接sql,如果是null,会影响testWhileIdle、testOnBorrow、testOnReturn失效,如果底层代码use-ping-method是true,默认使用ping
+      validation-query: SELECT 1
+      validation-query-timeout: 500
+      # 申请连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接
+      test-on-borrow: false
+      # 归还连接时会使用validationQuery检测连接是否有效,true会降低性能,如果是true,并且检测到连接已关闭,会获取其它的可用的连接,放回数据库线程池
+      test-on-return: false
+      # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果此连接空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
+      test-while-idle: true
+      # 1)配合testWhileIdle=true时使用,如果当前jdbc使用间隔大于timeBetweenEvictionRunsMillis配置的空闲连接过期时间,执行validationQuery检测连接是否有效。
+      # 数据库会主动超时并断开连接,因此建议timeBetweenEvictionRunsMillis小于数据库的连接主动断开时间(如mysql的wait_timeout和interactive_timeout)
+      # 2)配置间隔多久才进行一次检测,Destroy线程检测需要关闭的空闲连接的时间,单位是毫秒
+      time-between-eviction-runs-millis: 55000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      min-evictable-idle-time-millis: 30000
+      # max-evictable-idle-time-millis:
+      # 通过connectProperties属性来打开mergeSql功能;记录慢SQL
+      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+      filters: slf4j #sql文不允许写#注释,只可以在xml中写 <!--  -->注释
+      stat-view-servlet:
+        enabled: true
+        login-username: dongke
+        login-password: dongke
+        url-pattern: /druid/*
+        reset-enable: false
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.css,/druid/*"
+  redis:
+    host: s.dev01.dkiboss.com
+    port: 14000
+    password: dk
+  zipkin:
+    base-url: http://s.dev01.dkiboss.com:9411/
+    discovery-client-enabled: false
+    sleuth:
+      sampler:
+        probability: 1
+
+logback:
+  file: /data/java_project/dk_mes/${spring.application.name}/${spring.application.name}_logs
+
+feign:
+  sentinel:
+    enabled: true
+  client:
+    config:
+      default:
+        connectTimeout: 60000
+        readTimeout: 60000
+
+mybatis-plus:
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+  type-aliases-package: com.dk.oauth.dto,com.dk.common.infrastructure.handler #类型转换器包名
+  mapper-locations: classpath:/mapper/**/*Mapper.xml,com/hegii/scrm/common/mapper/opinfo/*.xml
+
+mybatis:
+  config-location: classpath:mybatis-config.xml
+
+swagger:
+  enabled: true
+
+dongke:
+  base:
+    pojo:
+      valid-key: flg_valid  #db有效标识
+      is-valid: true  #表示有效的值
+      un-valid: false  #表示无效的值
+      delete-key: flg_del  #db删除标识
+      is-delete: true  #表示删除的值
+      un-delete: false  #表示未删除的值
+    dynamic-ds:
+      ds-key: DS
+    ds:
+      table-name:
+
+#  单点登录是否开启
+single-sign-on: false
+uploadPath: ''
+printTemplatePath : ''
+
+aes-key: b6f64c1001b04b9f
+client-app-id: 48849faf-8bbb-4a29-9548-0ba1c3df963f
+
+excel-folder: /data/java_project/dk_mes/mdm-server/excel/
+

+ 19 - 0
src/main/resources/uat/bootstrap.yml

@@ -0,0 +1,19 @@
+server:
+  port: 6008
+spring:
+  application:
+    name: oauth-server
+  cloud:
+    nacos:
+      config:
+        file-extension: yaml
+        server-addr: ${NACOS_HOST:mse-ab4cb036-nacos-ans.mse.aliyuncs.com:8848}
+        namespace: ${NACOS_SPACE:hgscrm-uat}
+        shared-configs:
+          - data-id: common.yaml
+            group: DEFAULT_GROUP
+        group: ${group-id:DEFAULT_GROUP}
+      discovery:
+        server-addr: ${NACOS_HOST:mse-ab4cb036-nacos-ans.mse.aliyuncs.com:8848}
+        namespace: ${NACOS_SPACE:hgscrm-uat}
+

+ 106 - 0
src/main/webapp/WEB-INF/views/login.jsp

@@ -0,0 +1,106 @@
+<%@page contentType="text/html;charset=UTF-8" language="java" %>
+<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
+<html>
+<head>
+    <title>登录</title>
+</head>
+<style>
+    #iap-div{
+        border-radius: 10px;
+        margin:10em auto;
+        padding: 30px;
+        border: 1px solid #eeeeee;
+        width: 25em;
+        height: 20em;
+        background: rgb(179, 216, 255);
+    }
+    #iap-form {
+        margin: 64px auto;
+        width: 25em;
+        height: 20em;
+    }
+    #iap-password{
+        margin-top: 32px;
+    }
+    #submit{
+        position: relative;
+        top: 5%;
+        left: 18%;
+        right: 50%;
+        width: 23em;
+        display: inline-block;
+        line-height: 1;
+        white-space: nowrap;
+        cursor: pointer;
+        background: #ecf5ff;
+        border: 1px solid #dcdfe6;
+        color: #409eff;
+        -webkit-appearance: none;
+        text-align: center;
+        box-sizing: border-box;
+        outline: none;
+        margin: 0;
+        transition: .1s;
+        font-weight: 500;
+        -moz-user-select: none;
+        -webkit-user-select: none;
+        -ms-user-select: none;
+        padding: 12px 20px;
+        font-size: 14px;
+        border-radius: 4px;
+    }
+    #submit:hover{
+        background-color: #409eff;
+        border-color: #409eff;
+        color: #fff;
+    }
+    .iap-label{
+        text-align: right;
+        vertical-align: middle;
+        font-size: 15px;
+        color: #606266;
+        line-height: 40px;
+        padding: 0 12px 0 0;
+        box-sizing: border-box;
+    }
+    .iap-input{
+        -webkit-appearance: none;
+        background-color: #fff;
+        background-image: none;
+        border-radius: 4px;
+        border: 1px solid #dcdfe6;
+        box-sizing: border-box;
+        color: #606266;
+        display: inline-block;
+        font-size: inherit;
+        height: 40px;
+        line-height: 40px;
+        outline: none;
+        padding: 0 15px;
+        transition: border-color .2s cubic-bezier(.645,.045,.355,1);
+        width: 80%;
+    }
+    *:focus {
+        outline: none;
+        border:2px solid #409eff;
+        /*background-color: transparent;*/
+    }
+    ::selection{
+        /*background:transparent;*/
+    }
+    ::-moz-selection{
+        /*background:transparent;*/
+    }
+
+</style>
+<body style="margin: 0;padding: 0">
+<div id="iap-div">
+    <h2 style="text-align: center">IAP3.0</h2>
+    <form action="" method="post" d="reg" id="iap-form">
+        <span class="iap-label">用户名:</span><input type="text" class="iap-input" name="username" id="iap-username" value="<shiro:principal/>"><br/>
+        <span class="iap-label">密&nbsp;&nbsp;&nbsp;&nbsp;码:</span><input type="password" class="iap-input" name="password" id="iap-password"><br/>
+        <input type="submit" value="登录" id="submit">
+    </form>
+</div>
+</body>
+</html>

+ 125 - 0
src/main/webapp/WEB-INF/views/oauth2login.jsp

@@ -0,0 +1,125 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
+<html>
+<head>
+    <title>登录并授权</title>
+    <style>.error {
+        color: red;
+    }</style>
+</head>
+<style>
+    #iap-div {
+        border-radius: 10px;
+        margin: 10em auto;
+        padding: 30px;
+        border: 1px solid #eeeeee;
+        width: 25em;
+        height: 20em;
+        background: rgb(179, 216, 255);
+    }
+
+    #iap-form {
+        margin: 64px auto;
+        width: 25em;
+        height: 20em;
+    }
+
+    #iap-password {
+        margin-top: 32px;
+    }
+
+    #submit {
+        position: relative;
+        top: 5%;
+        left: 18%;
+        right: 50%;
+        width: 23em;
+        display: inline-block;
+        line-height: 1;
+        white-space: nowrap;
+        cursor: pointer;
+        background: #ecf5ff;
+        border: 1px solid #dcdfe6;
+        color: #409eff;
+        -webkit-appearance: none;
+        text-align: center;
+        box-sizing: border-box;
+        outline: none;
+        margin: 0;
+        transition: .1s;
+        font-weight: 500;
+        -moz-user-select: none;
+        -webkit-user-select: none;
+        -ms-user-select: none;
+        padding: 12px 20px;
+        font-size: 14px;
+        border-radius: 4px;
+    }
+
+    #submit:hover {
+        background-color: #409eff;
+        border-color: #409eff;
+        color: #fff;
+    }
+
+    .iap-label {
+        text-align: right;
+        vertical-align: middle;
+        font-size: 15px;
+        color: #606266;
+        line-height: 40px;
+        padding: 0 12px 0 0;
+        box-sizing: border-box;
+    }
+
+    .iap-input {
+        -webkit-appearance: none;
+        background-color: #fff;
+        background-image: none;
+        border-radius: 4px;
+        border: 1px solid #dcdfe6;
+        box-sizing: border-box;
+        color: #606266;
+        display: inline-block;
+        font-size: inherit;
+        height: 40px;
+        line-height: 40px;
+        outline: none;
+        padding: 0 15px;
+        transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
+        width: 80%;
+    }
+
+    *:focus {
+        outline: none;
+        border: 2px solid #409eff;
+        /*background-color: transparent;*/
+    }
+
+    ::selection {
+        /*background:transparent;*/
+    }
+
+    ::-moz-selection {
+        /*background:transparent;*/
+    }
+
+</style>
+<body style="margin: 0;padding: 0">
+<div id="iap-div">
+    <h2 style="text-align: center">IAP3.0</h2>
+    <div>Server帐号:[${client.clientName}]</div>
+    <div class="error">${error}</div>
+    <form action="/authorize" method="POST" id="iap-form">
+        <input type="text" name="response_type"  value="code" style="display: none">
+        <input type="text" name="redirect_uri"  value="${client.redirectUri}"  style="display: none">
+        <input type="text" name="client_id"  value="${client.clientId}"  style="display: none">
+        <input type="text" name="client_secret"  value="${client.clientSecret}"  style="display: none">
+        <input type="text" name="grant_type"  value="password"  style="display: none">
+        <span class="iap-label">用户名:</span><input type="text" name="username" class="iap-input" id="iap-username" value="<shiro:principal/>"><br/>
+        <span class="iap-label">密&nbsp;&nbsp;&nbsp;&nbsp;码:</span><input type="password" name="password" class="iap-input" id="iap-password"><br/>
+        <input type="submit" value="登录并授权" id="submit">
+    </form>
+</div>
+</body>
+</html>