From c87a0e4a519c8802dfb3fe808e7e5e71005a7c20 Mon Sep 17 00:00:00 2001 From: qiaowei Date: Fri, 14 Jun 2019 16:17:37 +0800 Subject: [PATCH] =?utf8?q?oauth=20server=20=E8=AE=A4=E8=AF=81=E6=A8=A1?= =?utf8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +- config/application-devel-pg.properties | 3 +- .../framework/filter/ValidateCodeFilter.java | 8 +- .../MyAuthenticationFailureHandler.java | 6 +- .../MyAuthenticationSuccessHandler.java | 1 + .../security/ValidateCodeSecurityConfig.java | 2 +- .../controller/security_controller.kt | 39 +++++++- src/main/kotlin/com/supwisdom/dlpay/oauth.kt | 45 +++++++-- .../kotlin/com/supwisdom/dlpay/security.kt | 40 +++++++- src/main/resources/templates/ologin.html | 91 +++++++++++++++++++ .../templates/system/operator/operator.html | 6 ++ 11 files changed, 216 insertions(+), 28 deletions(-) mode change 100755 => 100644 src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java create mode 100644 src/main/resources/templates/ologin.html diff --git a/build.gradle b/build.gradle index b11247b4..e318a0dc 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,7 @@ dependencies { 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 5bbedd3a..3c76bf53 100644 --- a/config/application-devel-pg.properties +++ b/config/application-devel-pg.properties @@ -19,4 +19,5 @@ jwt.secret=Zj5taLomEbrM0lk+NMQZbHfSxaDU1wekjT+kiC3YzDw= # 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 77242b9f..bfa90470 --- 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 @@ public class ValidateCodeFilter extends OncePerRequestFilter{ 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 bba039ed..e090b632 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 @@ public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailu } 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 f74d15da..abaa46a0 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 com.supwisdom.dlpay.api.bean.JsonResult; 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 56782db7..39416285 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 @@ import org.springframework.stereotype.Component; @Component("validateCodeSecurityConfig") public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter { - + @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 10f66030..5fb889e2 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 mu.KotlinLogging 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 @@ class ValidateCodeController { } } +@RestController +class UserInforController { + + @RequestMapping("/api/userinfor") + fun user(user:Principal ): Principal { + System.out.println(user) + return user + } +} + @Controller class WebMainController { @@ -184,8 +196,24 @@ class WebMainController { 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 @@ class WebMainController { 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 6f310a57..d46342c8 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.Aut 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 { +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() + 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() + 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 @@ class OAuth2Config { @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 30c0edde..1a9cd860 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.beans.factory.annotation.Autowired 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.config.http.SessionCreationPolicy 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.UsernamePasswordAuthentic 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 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { private var jwtUtil: JwtTokenUtil? = null + @Autowired + private lateinit var redisConnectionFactory: RedisConnectionFactory + private fun getUtil(): JwtTokenUtil { if (jwtUtil == null) { @@ -62,6 +71,23 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { } 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 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { } 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 @@ class WebSecurityConfig { // 设置 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 @@ class WebSecurityConfig { .antMatchers("/api/shop/**").hasRole("THIRD_SHOP") .anyRequest().hasRole("THIRD_COMMON") .and() - .csrf().ignoringAntMatchers("/api/**") + .csrf().ignoringAntMatchers("/api/**","oauth/**") } @Bean @@ -206,15 +238,15 @@ class WebSecurityConfig { .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 00000000..41302e1a --- /dev/null +++ b/src/main/resources/templates/ologin.html @@ -0,0 +1,91 @@ + + + + + + 统一身份认证 + + + + + + + + + + + + + \ 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 a048c1af..74bc4629 100644 --- a/src/main/resources/templates/system/operator/operator.html +++ b/src/main/resources/templates/system/operator/operator.html @@ -15,6 +15,12 @@ lay-verify="required" required/> +
+ +
+ +
+
-- 2.17.1