基本测试API认证,WebApp 认证,CSRF模块
diff --git a/build.gradle b/build.gradle
index d027592..6c9b719 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,6 +40,7 @@
implementation 'org.postgresql:postgresql:42.2.5'
implementation 'com.jcabi:jcabi-manifests:1.1'
implementation 'org.bitbucket.b_c:jose4j:0.6.3'
+ implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'org.springframework.social:spring-social-web:1.1.6.RELEASE'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
implementation group: 'com.sun.jersey', name: 'jersey-client', version: '1.19'
diff --git a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
index 3868edd..c7f5360 100755
--- a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
@@ -20,59 +20,59 @@
import java.io.IOException;
-@Component("validateCodeFilter")
-public class ValidateCodeFilter extends OncePerRequestFilter{
-
- /**
- * 校验失败处理器
- */
- @Autowired
- private AuthenticationFailureHandler myAuthenticationFailureHandler;
-
- /**
- * 校验成功处理器
- */
- @Autowired
- private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
-
-
- @Override
- protected void doFilterInternal(HttpServletRequest request,
- HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- if (StringUtil.equals("/login/form", request.getRequestURI())
- && StringUtil.equalsIgnoreCase(request.getMethod(), "post")) {
- try {
- validate(request);
- } catch (ValidateCodeException e) {
- myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
- }
- }
- filterChain.doFilter(request, response);
- }
-
- private void validate(HttpServletRequest request) throws ValidateCodeException {
- VerifyCode imageCode = (VerifyCode) request.getSession().getAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
- String inputCode;
- try {
- inputCode = request.getParameter("imageCode");
- } catch (Exception e) {
- throw new ValidateCodeException("获取验证码的值失败");
- }
- if (StringUtil.isEmpty(inputCode)) {
- throw new ValidateCodeException("验证码的值不能为空");
- }
- if (null == imageCode) {
- throw new ValidateCodeException("验证码不存在");
- }
- if (imageCode.isExpired()) {
- request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
- throw new ValidateCodeException("验证码已过期");
- }
- if (!StringUtil.equalsIgnoreCase(imageCode.getText(), inputCode)) {
- throw new ValidateCodeException("验证码不匹配");
- }
- request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
- }
-
-}
+//@Component("validateCodeFilter")
+//public class ValidateCodeFilter extends OncePerRequestFilter{
+//
+// /**
+// * 校验失败处理器
+// */
+// @Autowired
+// private AuthenticationFailureHandler myAuthenticationFailureHandler;
+//
+// /**
+// * 校验成功处理器
+// */
+// @Autowired
+// private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
+//
+//
+// @Override
+// protected void doFilterInternal(HttpServletRequest request,
+// HttpServletResponse response, FilterChain filterChain)
+// throws ServletException, IOException {
+// if (StringUtil.equals("/login/form", request.getRequestURI())
+// && StringUtil.equalsIgnoreCase(request.getMethod(), "post")) {
+// try {
+// validate(request);
+// } catch (ValidateCodeException e) {
+// myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
+// }
+// }
+// filterChain.doFilter(request, response);
+// }
+//
+// private void validate(HttpServletRequest request) throws ValidateCodeException {
+// VerifyCode imageCode = (VerifyCode) request.getSession().getAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
+// String inputCode;
+// try {
+// inputCode = request.getParameter("imageCode");
+// } catch (Exception e) {
+// throw new ValidateCodeException("获取验证码的值失败");
+// }
+// if (StringUtil.isEmpty(inputCode)) {
+// throw new ValidateCodeException("验证码的值不能为空");
+// }
+// if (null == imageCode) {
+// throw new ValidateCodeException("验证码不存在");
+// }
+// if (imageCode.isExpired()) {
+// request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
+// throw new ValidateCodeException("验证码已过期");
+// }
+// if (!StringUtil.equalsIgnoreCase(imageCode.getText(), inputCode)) {
+// throw new ValidateCodeException("验证码不匹配");
+// }
+// request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);
+// }
+//
+//}
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..c5c3f7c 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/ValidateCodeSecurityConfig.java
@@ -9,7 +9,7 @@
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.stereotype.Component;
-@Component("validateCodeSecurityConfig")
+//@Component("validateCodeSecurityConfig")
public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity> {
@Autowired
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/validate/VerifyCode.java b/src/main/java/com/supwisdom/dlpay/framework/security/validate/VerifyCode.java
index 26d6ea5..74cc240 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/validate/VerifyCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/validate/VerifyCode.java
@@ -5,10 +5,11 @@
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Random;
-public class VerifyCode {
+public class VerifyCode implements Serializable {
private int w = 100;
private int h = 35;
private Random r = new Random();
@@ -120,4 +121,6 @@
public boolean isExpired(){
return LocalDateTime.now().isAfter(localDateTime);
}
+
+
}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt b/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
index 7ff33c6..580ee13 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
@@ -1,10 +1,6 @@
package com.supwisdom.dlpay
-import com.supwisdom.dlpay.framework.filter.ValidateCodeFilter
-import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler
-import com.supwisdom.dlpay.framework.security.MyAuthenticationSuccessHandler
import io.lettuce.core.ReadFrom
-import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@@ -15,7 +11,10 @@
import org.springframework.data.redis.connection.RedisStandaloneConfiguration
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
+import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
+import org.springframework.data.redis.serializer.StringRedisSerializer
@Configuration
@@ -49,6 +48,22 @@
}
}
+@Configuration
+class HttpSessionConfig {
+ @Bean
+ fun sessionRedisTemplate(
+ connectionFactory: RedisConnectionFactory): RedisTemplate<Any, Any> {
+ val template = RedisTemplate<Any, Any>()
+ template.keySerializer = StringRedisSerializer()
+ template.hashKeySerializer = StringRedisSerializer()
+
+ template.setDefaultSerializer(GenericJackson2JsonRedisSerializer())
+ template.setConnectionFactory(connectionFactory)
+ return template
+ }
+}
+
+
@SpringBootApplication
class PayApiApplication
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 cd7d60f..3e13e8b 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
@@ -15,9 +15,7 @@
import org.springframework.http.ResponseEntity
import org.springframework.social.connect.web.HttpSessionSessionStrategy
import org.springframework.stereotype.Controller
-import org.springframework.web.bind.annotation.GetMapping
-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.util.*
import javax.imageio.ImageIO
@@ -103,7 +101,7 @@
}
@RestController
-class ValidateCodeController{
+class ValidateCodeController {
@GetMapping("/code/image")
fun createCode(request: HttpServletRequest, response: HttpServletResponse) {
@@ -113,6 +111,9 @@
}
}
+
+data class LoginForm(val username: String, val password: String, val imageCode: String)
+
@Controller
class WebHomeController {
@@ -121,4 +122,10 @@
@GetMapping("/login")
fun loginView() = "login"
+
+ @PostMapping("/login/form")
+ fun loginForm(form: LoginForm): String {
+ println(form.username)
+ return "index"
+ }
}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index b529714..29c795d 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -2,10 +2,6 @@
import com.supwisdom.dlpay.framework.core.JwtConfig
import com.supwisdom.dlpay.framework.core.JwtTokenUtil
-import com.supwisdom.dlpay.framework.filter.ValidateCodeFilter
-import com.supwisdom.dlpay.framework.security.MyInvalidSessionStrategy
-import com.supwisdom.dlpay.framework.security.ValidateCodeSecurityConfig
-import com.supwisdom.dlpay.framework.service.OperatorDetailService
import org.jose4j.jwt.consumer.InvalidJwtException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
@@ -19,21 +15,14 @@
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.core.session.SessionRegistry
-import org.springframework.security.core.session.SessionRegistryImpl
-import org.springframework.security.core.userdetails.User
-import org.springframework.security.core.userdetails.UserDetailsService
-import org.springframework.security.provisioning.InMemoryUserDetailsManager
-import org.springframework.security.web.authentication.AuthenticationFailureHandler
-import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
-import org.springframework.security.web.session.InvalidSessionStrategy
-import org.springframework.security.web.session.SessionInformationExpiredStrategy
+import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
import org.springframework.web.filter.OncePerRequestFilter
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
+import javax.sql.DataSource
class ApiJwtAuthenticationFilter(jwt: JwtTokenUtil) : OncePerRequestFilter() {
@@ -79,10 +68,10 @@
@Autowired
lateinit var jwtConfig: JwtConfig
+
override fun configure(http: HttpSecurity) {
// 设置 API 访问权限管理
- http.csrf().disable()
- .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterAfter(ApiJwtAuthenticationFilter(JwtTokenUtil(jwtConfig)),
UsernamePasswordAuthenticationFilter::class.java)
@@ -91,50 +80,58 @@
.antMatchers("/api/common/**").hasAnyRole("THIRD_COMMON", "THIRD_ADMIN")
.antMatchers("/api/consume/**").hasRole("THIRD_CONSUME")
.antMatchers("/api/deposit/**").hasRole("THIRD_DEPOSIT")
- .antMatchers("/api/user/**").hasAnyRole("THIRD_COMMON", "THIRD_ADMIN")
+ .antMatchers("/api/user/**").hasRole("THIRD_ADMIN")
.antMatchers("/api/shop/**").hasRole("THIRD_SHOP")
- // 注册 filter
+ .and()
+ .csrf().ignoringAntMatchers("/api/**")
}
}
@Configuration
class MvcWebSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() {
@Autowired
- lateinit var validateCodeSecurityConfig: ValidateCodeSecurityConfig
- @Autowired
- lateinit var userDetailsService: OperatorDetailService
- @Autowired
- lateinit var myAuthenticationFailureHandler: AuthenticationFailureHandler
- @Autowired
- lateinit var myAuthenticationSuccessHandler: AuthenticationSuccessHandler
- @Autowired
- lateinit var myInvalidSessionStrategy: InvalidSessionStrategy
+ lateinit var dataSource: DataSource
+// @Autowired
+// lateinit var validateCodeSecurityConfig: ValidateCodeSecurityConfig
+// @Autowired
+// lateinit var userDetailsService: OperatorDetailService
+// @Autowired
+// lateinit var myAuthenticationFailureHandler: AuthenticationFailureHandler
+// @Autowired
+// lateinit var myAuthenticationSuccessHandler: AuthenticationSuccessHandler
+// @Autowired
+// lateinit var myInvalidSessionStrategy: InvalidSessionStrategy
+ @Bean
+ fun jdbcTokenImplement(): JdbcTokenRepositoryImpl {
+ return JdbcTokenRepositoryImpl().also {
+ it.setDataSource(dataSource)
+ }
+ }
+
override fun configure(http: HttpSecurity) {
// 设置 Web MVC 应用权限
- http.apply(validateCodeSecurityConfig)
+ http.csrf()
+ .and()
+ .authorizeRequests()
+ .antMatchers("/login", "/login/form").permitAll()
+ .antMatchers("/static/**").permitAll()
+ .antMatchers("/code/image").permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .sessionManagement()
+ .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/form")
- .successHandler(myAuthenticationSuccessHandler)
- .failureHandler(myAuthenticationFailureHandler)
.and()
.logout()
.logoutRequestMatcher(AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
- .and()
- .userDetailsService(userDetailsService)
- .authorizeRequests()
- .antMatchers("/login").permitAll()
- .antMatchers("/static/**").permitAll()
- .antMatchers("/code/image").permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin()
// 设置 Web MVC 应用权限
// http.apply(validateCodeSecurityConfig)
// .and()
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 0a24848..6abc8d8 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,10 +1,5 @@
#######################################springboot配置 start#################################
# 单库数据库配置
-spring.datasource.url=jdbc:oracle:thin:@172.28.201.101:47922:orcl
-spring.datasource.username=dlpay
-spring.datasource.password=kingstar
-spring.datasource.driver.class=oracle.jdbc.driver.OracleDriver
-spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.jpa.show-sql=true
spring.datasource.hikari.connection-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
@@ -23,14 +18,3 @@
spring.thymeleaf.mode=HTML5
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=true
-#################### Redis ####################
-# Redis settings
-redis.server=172.28.201.101
-redis.port=16379
-redis.password=kingstar
-redis.database=0
-#################### jwt ####################
-# jwt settings
-jwt.secret=Zj5taLomEbrM0lk+NMQZbHfSxaDU1wekjT+kiC3YzDw=
-jwt.expiration=3600
-jwt.header=payapi
\ No newline at end of file
diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html
index 4feb52a..919d862 100644
--- a/src/main/resources/templates/login.html
+++ b/src/main/resources/templates/login.html
@@ -1,12 +1,15 @@
<!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/payapi/css/login.css}" />
</head>
-
<body>
<div class="login-wrapper">
@@ -25,6 +28,9 @@
<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">