oauth server 认证模块
diff --git a/build.gradle b/build.gradle
index b11247b..e318a0d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,8 +30,7 @@
     implementation 'org.springframework.boot:spring-boot-starter-security'
     implementation 'org.springframework.security:spring-security-oauth2-client'
     implementation 'org.springframework.security:spring-security-oauth2-jose'
-    implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.1.RELEASE'
-//    implementation 'org.springframework.security.oauth:spring-security-oauth2'
+    implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.5.RELEASE'
     implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
     implementation 'org.springframework.session:spring-session-data-redis'
     implementation 'org.springframework.boot:spring-boot-starter-cache'
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 5bbedd3..3c76bf5 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -19,4 +19,5 @@
 # timeout seconds
 jwt.expiration=3600
 auth.password.bcrypt.seed=
-spring.jackson.serialization.fail-on-empty-beans=false
\ No newline at end of file
+spring.jackson.serialization.fail-on-empty-beans=false
+logging.level.org.springframework.web=DEBUG
\ No newline at end of file
diff --git a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
old mode 100755
new mode 100644
index 77242b9..bfa9047
--- a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
@@ -48,11 +48,11 @@
 			try {

 				validate(request);

 			} catch (ValidateCodeException e) {

-				response.setStatus(HttpStatus.OK.value());

-				response.setContentType("application/json;charset=UTF-8");

-				response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, e.getMessage())));

+				//response.setStatus(HttpStatus.OK.value());

+				//response.setContentType("application/json;charset=UTF-8");

+				//response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, e.getMessage())));

 				//response.sendError(HttpStatus.UNAUTHORIZED.value(),e.getMessage());

-				//myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);

+				myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);

 				return;

 			}

 		}

diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
index bba039e..e090b63 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
@@ -37,9 +37,11 @@
     } else if (exception instanceof ValidateCodeException) {
       errmsg = exception.getMessage();
     }
-    response.setStatus(HttpStatus.OK.value());
+    setDefaultFailureUrl("/login");
+    super.onAuthenticationFailure(request, response, new ValidateCodeException(errmsg));
+    /*response.setStatus(HttpStatus.OK.value());
     response.setContentType("application/json;charset=UTF-8");
-    response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, errmsg)));
+    response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, errmsg)));*/
   }
 
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
index f74d15d..abaa46a 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
@@ -5,6 +5,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
 import org.springframework.stereotype.Component;
 
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java b/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java
index 56782db..3941628 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java
@@ -11,7 +11,7 @@
 
 @Component("validateCodeSecurityConfig")
 public class ValidateCodeSecurityConfig  extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity> {
-	
+
 	@Autowired
 	private Filter validateCodeFilter;
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
index 10f6603..5fb889e 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
@@ -21,18 +21,20 @@
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
+import org.springframework.security.core.Authentication
 import org.springframework.security.core.annotation.AuthenticationPrincipal
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.security.core.userdetails.UserDetails
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
+import org.springframework.security.oauth2.provider.OAuth2Authentication
 import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler
 import org.springframework.social.connect.web.HttpSessionSessionStrategy
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.PathVariable
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
 import org.springframework.web.context.request.ServletWebRequest
+import java.io.IOException
+import java.security.Principal
 import java.util.*
 import javax.imageio.ImageIO
 import javax.servlet.http.HttpServletRequest
@@ -173,6 +175,16 @@
     }
 }
 
+@RestController
+class UserInforController {
+
+    @RequestMapping("/api/userinfor")
+    fun user(user:Principal ): Principal {
+        System.out.println(user)
+        return user
+    }
+}
+
 
 @Controller
 class WebMainController {
@@ -184,8 +196,24 @@
     private val logger = KotlinLogging.logger {}
 
     @GetMapping("/login")
-    fun loginView() = "login"
+    fun loginView() = "ologin"
 
+    @RequestMapping("/third/logout")
+    fun oauthLogout(request:HttpServletRequest,response:HttpServletResponse ) {
+        val back = request.getParameter("redirect_uri")
+        SecurityContextLogoutHandler().logout(request, null, null);
+        try {
+            SecurityContextHolder.getContext().authentication = null
+            if(back!=null){
+                response.sendRedirect(back)
+            }else{
+                logger.debug { request.getHeader("referer") }
+                response.sendRedirect(request.getHeader("referer"))
+            }
+        } catch (e: IOException) {
+            e.printStackTrace()
+        }
+    }
     @GetMapping("/logout")
     fun logout(request: HttpServletRequest, response: HttpServletResponse): String {
         SecurityContextHolder.getContext().authentication?.also {
@@ -203,6 +231,7 @@
         model.addAttribute("payapiVersion", commonService.getSystemVersion())
         return "index"
     }
+
 }
 
 @Controller
diff --git a/src/main/kotlin/com/supwisdom/dlpay/oauth.kt b/src/main/kotlin/com/supwisdom/dlpay/oauth.kt
index 6f310a5..d46342c 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/oauth.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/oauth.kt
@@ -1,9 +1,13 @@
 package com.supwisdom.dlpay
 
+import com.supwisdom.dlpay.system.service.ParamService
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.context.annotation.Configuration
 import org.springframework.data.redis.connection.RedisConnectionFactory
 import org.springframework.security.authentication.AuthenticationManager
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.GrantedAuthority
+import org.springframework.security.core.authority.SimpleGrantedAuthority
 import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer
 import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter
 import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer
@@ -14,28 +18,50 @@
 import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer
 import org.springframework.security.oauth2.provider.ClientDetails
 import org.springframework.security.oauth2.provider.ClientDetailsService
+import org.springframework.security.oauth2.provider.client.BaseClientDetails
+import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter
 import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore
+import java.util.*
+import org.springframework.security.oauth2.provider.token.TokenStore
+
+
 
 
 class OAuthDetailService : ClientDetailsService {
-
+    @Autowired
+    private lateinit var paramService: ParamService;
     override fun loadClientByClientId(clientId: String?): ClientDetails {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        val details = BaseClientDetails()
+        if (clientId.isNullOrEmpty()) {
+            return details
+        }
+        details.clientId = clientId
+        paramService.getApiClientByAppid(clientId)?.let {
+            details.setAuthorizedGrantTypes(Arrays.asList("password","authorization_code","refresh_token"))
+            details.setScope(Arrays.asList("read"))
+            details.setResourceIds(Arrays.asList("oauth2-resource"))
+            val authorities = HashSet<GrantedAuthority>()
+            authorities.add(SimpleGrantedAuthority("ROLE_THIRD_ADMIN"))
+            details.authorities = authorities
+            details.setAutoApproveScopes(Arrays.asList("true"))
+            details.clientSecret = it.secret
+            details.accessTokenValiditySeconds = 3600
+            details.refreshTokenValiditySeconds=43200
+            val redir = HashSet<String>()
+            redir.add("http://localhost:8091/wt/sso/login")
+            details.registeredRedirectUri = redir
+        }
+        return details
     }
 }
 
+
 @Configuration
 class OAuth2Config {
-    @Configuration
-    @EnableResourceServer
-    class ResourceServerConfiguration : ResourceServerConfigurerAdapter() {
-        override fun configure(resources: ResourceServerSecurityConfigurer?) {
-            resources?.resourceId("payapi")?.stateless(true)
-        }
-    }
 
     @Configuration
     @EnableAuthorizationServer
+
     class AuthorizationServerConfigure : AuthorizationServerConfigurerAdapter() {
 
         @Autowired
@@ -44,6 +70,7 @@
         @Autowired
         private lateinit var authenticationManager: AuthenticationManager
 
+
         override fun configure(security: AuthorizationServerSecurityConfigurer?) {
             security?.allowFormAuthenticationForClients()
         }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index 30c0edd..1a9cd86 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -15,6 +15,7 @@
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.core.annotation.Order
+import org.springframework.data.redis.connection.RedisConnectionFactory
 import org.springframework.http.HttpStatus
 import org.springframework.security.authentication.AuthenticationManager
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
@@ -28,6 +29,8 @@
 import org.springframework.security.core.authority.SimpleGrantedAuthority
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore
 import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
 import org.springframework.security.web.authentication.AuthenticationFailureHandler
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler
@@ -35,7 +38,10 @@
 import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher
 import org.springframework.stereotype.Component
+import org.springframework.util.StringUtils
 import org.springframework.web.filter.OncePerRequestFilter
+import org.springframework.web.servlet.DispatcherServlet
+import org.springframework.web.servlet.view.RedirectView
 import java.security.SecureRandom
 import javax.servlet.FilterChain
 import javax.servlet.http.HttpServletRequest
@@ -53,6 +59,9 @@
 
     private var jwtUtil: JwtTokenUtil? = null
 
+    @Autowired
+    private lateinit var redisConnectionFactory: RedisConnectionFactory
+
 
     private fun getUtil(): JwtTokenUtil {
         if (jwtUtil == null) {
@@ -62,6 +71,23 @@
     }
 
     override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
+        var context: String? = request.contextPath
+        if (context == null || "" == context.trim { it <= ' ' }) {
+            context = "/"
+        }
+        if(request.requestURI.isEmpty()){
+            filterChain.doFilter(request, response)
+            return
+        }
+        var url = request.requestURI
+        if ("/" != context) {
+            url = url.replace(context,"")
+        }
+        logger.info(url)
+        if(!url.startsWith("/api/")){
+            filterChain.doFilter(request, response)
+            return
+        }
         request.getHeader(jwtConfig.header)?.let { authHeader ->
             try {
                 val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
@@ -69,6 +95,11 @@
                 } else {
                     throw JoseException("JWT Header error")
                 }
+                if(url.contains("/userinfor")){
+                    SecurityContextHolder.getContext().authentication = RedisTokenStore(redisConnectionFactory).readAuthentication(jwt)
+                    filterChain.doFilter(request, response)
+                    return
+                }
                 val claims = getUtil().verifyToken(jwt)
                 apiJwtRepository.findById(claims["jti"].toString()).let {
                     if (!it.isPresent) {
@@ -118,12 +149,13 @@
                 // 设置 API 访问权限管理
                 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                         .and()
+                        .antMatcher("/api/**")
                         .addFilterAfter(apiFilter,
                                 UsernamePasswordAuthenticationFilter::class.java)
-                        .antMatcher("/api/**")
                         .authorizeRequests()
                         .antMatchers("/api/auth/**").permitAll()
                         .antMatchers("/api/notify/**").permitAll()
+                        .antMatchers("/api/userinfor").hasAnyRole("ADMIN","THIRD_ADMIN")
                         .antMatchers("/api/common/**").hasAnyRole("THIRD_COMMON", "THIRD_ADMIN")
                         .antMatchers("/api/consume/**").hasRole("THIRD_CONSUME")
                         .antMatchers("/api/deposit/**").hasRole("THIRD_DEPOSIT")
@@ -131,7 +163,7 @@
                         .antMatchers("/api/shop/**").hasRole("THIRD_SHOP")
                         .anyRequest().hasRole("THIRD_COMMON")
                         .and()
-                        .csrf().ignoringAntMatchers("/api/**")
+                        .csrf().ignoringAntMatchers("/api/**","oauth/**")
             }
 
             @Bean
@@ -206,15 +238,15 @@
                         .formLogin()
                         .loginPage("/login")
                         .loginProcessingUrl("/login/form")
-                        .successHandler(authenticationSuccessHandler)
                         .failureHandler(authenticationFailureHandler)
+                        .defaultSuccessUrl("/",false)
                         .and()
                         .logout()
                         .logoutRequestMatcher(AntPathRequestMatcher("/logout"))
                         .logoutSuccessUrl("/login")
                         .deleteCookies("JSESSIONID")
                         .invalidateHttpSession(true)
-                        .and().csrf()
+                        .and().csrf().ignoringAntMatchers("oauth/**")
                 // 设置 Web MVC 应用权限
 //                http.apply(validateCodeSecurityConfig)
 //                        .and()
diff --git a/src/main/resources/templates/ologin.html b/src/main/resources/templates/ologin.html
new file mode 100644
index 0000000..41302e1
--- /dev/null
+++ b/src/main/resources/templates/ologin.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+<head>
+    <title>统一身份认证</title>
+    <meta name="_csrf" th:content="${_csrf.token}"/>
+    <!-- default header name is X-CSRF-TOKEN -->
+    <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
+    <link rel="stylesheet" type="text/css" th:href="@{/static/libs/layui/css/layui.css}"/>
+    <link rel="stylesheet" type="text/css" th:href="@{/static/custom/css/login.css}"/>
+</head>
+<body>
+<div class="login-wrapper">
+    <div class=" login-body">
+        <div class="layui-card">
+            <div class="layui-card-header">
+                <i class="layui-icon layui-icon-engine"></i>&nbsp;&nbsp;统一身份认证
+            </div>
+            <div class="layui-card-body layui-form layui-form-pane">
+                <p style="color:red;padding: 0 0 10px 0;" th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']!=null and session['SPRING_SECURITY_LAST_EXCEPTION'].message!=null}" th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}"></p>
+                <form th:action="@{/login/form}" method="post">
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-username"></i></label>
+                        <div class="layui-input-block">
+                            <input name="username" type="text" lay-verify="required" placeholder="账号"
+                                   class="layui-input">
+                            <input type="hidden"
+                                   th:name="${_csrf.parameterName}"
+                                   th:value="${_csrf.token}"/>
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-password"></i></label>
+                        <div class="layui-input-block">
+                            <input name="password" type="password" lay-verify="required" placeholder="密码"
+                                   class="layui-input">
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-vercode"></i></label>
+                        <div class="layui-input-block">
+                            <div class="layui-row inline-block">
+                                <div class="layui-col-xs7">
+                                    <input name="imageCode" type="text" placeholder="验证码"
+                                           class="layui-input">
+                                </div>
+                                <div class="layui-col-xs5" style="padding-left: 10px;">
+                                    <img width="100px" height="35px" class="login-captcha" th:src="@{/code/image}">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <!--<a href="javascript:;" class="layui-link">帐号注册</a>-->
+                        <a href="javascript:;" class="layui-link pull-right">忘记密码?</a>
+                    </div>
+                    <div class="layui-form-item">
+                        <button type="submit" lay-filter="login-submit" class="layui-btn layui-btn-fluid" lay-submit>登 录</button>
+                    </div>
+                </form>
+                <!--<div class="layui-form-item login-other">-->
+                <!--<label>第三方登录</label>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-qq"></i></a>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-wechat"></i></a>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-weibo"></i></a>-->
+                <!--</div>-->
+            </div>
+        </div>
+    </div>
+
+    <div class="login-footer">
+        <p>© 2019 <a href="javascript:;" target="_blank">上海树维信息科技有限公司 版权所有</a></p>
+        <!--<p>-->
+        <!--<span><a href="javascript:;" target="_blank">前往github</a></span>-->
+        <!--<span><a href="https://gitee.com/andyzy/zy-admin.git" target="_blank">前往gitee</a></span>-->
+        <!--<span><a href="javascript:;" target="_blank">文档说明</a></span>-->
+        <!--</p>-->
+    </div>
+</div>
+
+<script type="text/javascript"  th:src="@{/static/libs/layui/layui.js}" ></script>
+<script>
+    layui.config({
+        base: 'custom/module/'
+    }).use(['form'], function () {
+        var $ = layui.jquery;
+    });
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/operator/operator.html b/src/main/resources/templates/system/operator/operator.html
index a048c1a..74bc462 100644
--- a/src/main/resources/templates/system/operator/operator.html
+++ b/src/main/resources/templates/system/operator/operator.html
@@ -16,6 +16,12 @@
         </div>
     </div>
     <div class="layui-form-item">
+        <label class="layui-form-label" title="用于第三方授权登录,但不能访问本系统资源">授权登录用户</label>
+        <div class="layui-input-block">
+            <input type="checkbox" name="thirdadmin" value="yes"  />
+        </div>
+    </div>
+    <div class="layui-form-item">
         <label class="layui-form-label">性别</label>
         <div class="layui-input-block">
             <input type="radio" name="sex" value="male" title="男" checked/>