From d09629a57862d25e7d90d4f120cda14eed960e2a Mon Sep 17 00:00:00 2001 From: qiaowei Date: Wed, 26 Jun 2019 15:11:32 +0800 Subject: [PATCH] =?utf8?q?=E6=89=8B=E6=9C=BA=E7=AB=AFAPI=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- config/application-devel-pg.properties | 6 +- .../framework/filter/ValidateCodeFilter.java | 122 ++++++++-------- .../framework/redisrepo/ApiJwtRepository.java | 1 + .../dlpay/mobile/AuthLoginHandler.kt | 113 +++++++++++++++ .../com/supwisdom/dlpay/mobile/MobileApi.kt | 38 +++++ .../dlpay/mobile/dao/MobileUserDao.kt | 10 ++ .../dlpay/mobile/domain/TBMobileUser.kt | 136 ++++++++++++++++++ .../exception/UserLoginFailException.kt | 7 + .../dlpay/mobile/service/MobileApiService.kt | 9 ++ .../dlpay/mobile/service/MobileUserService.kt | 5 + .../service/impl/MobileApiServiceImpl.kt | 19 +++ .../service/impl/MobileUserServiceImpl.kt | 37 +++++ .../kotlin/com/supwisdom/dlpay/security.kt | 79 +++++++++- 13 files changed, 513 insertions(+), 69 deletions(-) create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/dao/MobileUserDao.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/exception/UserLoginFailException.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileApiService.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileUserService.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileApiServiceImpl.kt create mode 100644 src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileUserServiceImpl.kt diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties index 5ea16f5c..61b2df94 100644 --- a/config/application-devel-pg.properties +++ b/config/application-devel-pg.properties @@ -24,4 +24,8 @@ logging.level.org.springframework.web=DEBUG security.request.sign=false ################################################## ## quartz task scheduler -shopbalance.updater.cron=- \ No newline at end of file +<<<<<<< HEAD +shopbalance.updater.cron=- +======= +shopbalance.updater.cron = - +>>>>>>> 手机端API认证 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 16e429ab..7255657c 100644 --- a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java +++ b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java @@ -1,16 +1,12 @@ package com.supwisdom.dlpay.framework.filter; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.supwisdom.dlpay.api.bean.JsonResult; import com.supwisdom.dlpay.exception.ValidateCodeException; +import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler; import com.supwisdom.dlpay.framework.security.validate.ImageCodeUtil; import com.supwisdom.dlpay.framework.security.validate.VerifyCode; import com.supwisdom.dlpay.framework.util.StringUtil; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.security.web.authentication.AuthenticationFailureHandler; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -22,65 +18,69 @@ import java.io.IOException; @Component("validateCodeFilter") -public class ValidateCodeFilter extends OncePerRequestFilter{ +public class ValidateCodeFilter extends OncePerRequestFilter { - /** - * 校验失败处理器 - */ - @Autowired - private AuthenticationFailureHandler myAuthenticationFailureHandler; + /** + * 校验失败处理器 + */ + @Autowired + private MyAuthenticationFailureHandler myAuthenticationFailureHandler; - /** - * 校验成功处理器 - */ - @Autowired - private AuthenticationSuccessHandler myAuthenticationSuccessHandler; - @Autowired - private ObjectMapper objectMapper; + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + String context = request.getContextPath(); + if (context == null || "" == context.trim()) { + context = "/"; + } + if (request.getRequestURI().isEmpty()) { + filterChain.doFilter(request, response); + return; + } + String url = request.getRequestURI(); + if (!"/".equals(context)) { + url = url.replace(context, ""); + } + if (StringUtil.equals("/login/form", url) + && StringUtil.equalsIgnoreCase(request.getMethod(), "post")) { + 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.sendError(HttpStatus.UNAUTHORIZED.value(),e.getMessage()); + myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e); + return; + } + } + filterChain.doFilter(request, response); + } - @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) { - //response.setTransStatus(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); - return; - } - } - 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); - } + 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/redisrepo/ApiJwtRepository.java b/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java index 38a3fbe6..3371b31f 100644 --- a/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java +++ b/src/main/java/com/supwisdom/dlpay/framework/redisrepo/ApiJwtRepository.java @@ -2,6 +2,7 @@ package com.supwisdom.dlpay.framework.redisrepo; import com.supwisdom.dlpay.framework.domain.JwtRedis; import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; public interface ApiJwtRepository extends CrudRepository { } diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt new file mode 100644 index 00000000..e1b58697 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/AuthLoginHandler.kt @@ -0,0 +1,113 @@ +package com.supwisdom.dlpay.mobile + +import com.fasterxml.jackson.databind.ObjectMapper +import com.supwisdom.dlpay.api.bean.JsonResult +import com.supwisdom.dlpay.exception.ValidateCodeException +import com.supwisdom.dlpay.framework.core.JwtConfig +import com.supwisdom.dlpay.framework.core.JwtTokenUtil +import com.supwisdom.dlpay.framework.domain.JwtRedis +import com.supwisdom.dlpay.framework.redisrepo.ApiClientRepository +import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository +import com.supwisdom.dlpay.framework.util.DateUtil +import com.supwisdom.dlpay.framework.util.TradeDict +import com.supwisdom.dlpay.mobile.dao.MobileUserDao +import com.supwisdom.dlpay.mobile.domain.TBMobileUser +import com.supwisdom.dlpay.mobile.exception.UserLoginFailException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.security.authentication.BadCredentialsException +import org.springframework.security.authentication.LockedException +import org.springframework.security.core.Authentication +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler +import org.springframework.stereotype.Component +import java.io.IOException +import javax.servlet.ServletException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + +@Component("authLoginSuccessHandler") +class AuthLoginSuccessHandler : SimpleUrlAuthenticationSuccessHandler() { + @Autowired + lateinit var mobileUserDao: MobileUserDao + @Autowired + lateinit var objectMapper: ObjectMapper + @Autowired + lateinit var jwtConfig: JwtConfig + @Autowired + lateinit var apiJwtRepository: ApiJwtRepository + + override fun onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) { + logger.error(request?.getParameter("platform")) + var temp = authentication!!.principal as TBMobileUser + var user = mobileUserDao.findByPhone(temp.phone) + if(user!=null) { + //TODO 从数据取jwtConfig.expiration + val token = JwtTokenUtil(jwtConfig).generateToken( + mapOf("uid" to user.uid, "issuer" to "payapi", + "audience" to temp.phone, + "authorities" to temp.authorities)) + var jwt = JwtRedis().apply { + jti = token.jti + uid = temp.phone + status = TradeDict.JWT_STATUS_NORMAL + expiration = token.expiration.valueInMillis + }.apply { + //删除之前的token + if(!user.jti.isNullOrEmpty()){ + apiJwtRepository.deleteById(user.jti!!) + } + apiJwtRepository.save(this) + } + if (user.loginpwderror != null && user.loginpwderror!! > 0) { + user.loginpwderror = 0 + user.loginpwderrortime = null + } + user.lastlogin = DateUtil.getNow() + user.jti = jwt.jti + mobileUserDao.save(user) + response.status = HttpStatus.OK.value() + response.contentType = "application/json;charset=UTF-8" + response.writer.write(objectMapper.writeValueAsString(JsonResult.ok().put("token", token.jwtToken))) + }else{ + throw UserLoginFailException("登录错误") + } + } +} + + +@Component("authLoginFailHandler") +class AuthLoginFailHandler : SimpleUrlAuthenticationFailureHandler() { + @Autowired + lateinit var mobileUserDao: MobileUserDao + + @Autowired + lateinit var objectMapper: ObjectMapper + + @Throws(IOException::class, ServletException::class) + override fun onAuthenticationFailure(request: HttpServletRequest, + response: HttpServletResponse, exception: AuthenticationException) { + logger.error("登录失败:" + exception.message + "|" + exception.javaClass) + var errmsg = "" + if (exception is BadCredentialsException) { + errmsg = "手机号或密码错误" + } else if (exception is LockedException) { + errmsg = "账户被锁定" + } else { + errmsg = exception.message!! + } + var temp = request.getParameter("username") + mobileUserDao.findByPhone(temp)?.let { + if (it.loginpwderror == null || it.loginpwderror == 0) { + it.loginpwderror = 0 + it.loginpwderrortime = System.currentTimeMillis() + } + it.loginpwderror += 1 + mobileUserDao.save(it) + } + response.status = HttpStatus.OK.value() + response.contentType = "application/json;charset=UTF-8" + response.writer.write(objectMapper.writeValueAsString(JsonResult.error(errmsg))) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt new file mode 100644 index 00000000..a39db676 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt @@ -0,0 +1,38 @@ +package com.supwisdom.dlpay.mobile + +import com.supwisdom.dlpay.api.bean.JsonResult +import com.supwisdom.dlpay.mobile.service.MobileUserService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import org.springframework.web.bind.annotation.RequestMethod +import java.security.Principal + + +@RestController +@RequestMapping("/mobileapi") +class MobileApiController { + @Autowired + lateinit var userService: MobileUserService + @RequestMapping("/logout") + fun logout(request: HttpServletRequest, response: HttpServletResponse): JsonResult { + SecurityContextHolder.getContext().authentication?.also { + SecurityContextLogoutHandler().logout(request, response, it) + } + return JsonResult.ok("退出成功") + } +} + +@RestController +@RequestMapping("/mobileapi/v1") +class ApiV1 { + @RequestMapping("/infor") + fun getUserInfor(): JsonResult { + val p = SecurityContextHolder.getContext().authentication + return JsonResult.ok("OK") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/dao/MobileUserDao.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/dao/MobileUserDao.kt new file mode 100644 index 00000000..52615868 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/dao/MobileUserDao.kt @@ -0,0 +1,10 @@ +package com.supwisdom.dlpay.mobile.dao + +import com.supwisdom.dlpay.mobile.domain.TBMobileUser +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface MobileUserDao : JpaRepository { + fun findByPhone(phone: String): TBMobileUser? +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt new file mode 100644 index 00000000..da95e4f4 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt @@ -0,0 +1,136 @@ +package com.supwisdom.dlpay.mobile.domain + +import com.supwisdom.dlpay.framework.util.TradeDict +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.userdetails.UserDetails +import javax.persistence.* + +@Entity +@Table(name = "TB_MOBILE_USER") +class TBMobileUser : UserDetails { + override fun getAuthorities(): Collection? { + return this.auths + } + + override fun isEnabled(): Boolean { + return TradeDict.STATUS_CLOSED != this.status + } + + override fun getUsername(): String { + return this.phone + } + + override fun isCredentialsNonExpired(): Boolean { + return true + } + + override fun getPassword(): String { + return this.loginpwd + } + + override fun isAccountNonExpired(): Boolean { + return true + } + + override fun isAccountNonLocked(): Boolean { + return TradeDict.STATUS_LOCKED != this.status + } + @Transient + var auths: Collection? = null + + + @Id + @Column(name = "uid", nullable = false, length = 32) + var uid: String = "" + /** + * 手机号 + * */ + @Column(name = "phone", length = 15) + var phone: String = "" + + /** + * 设备uuid + * */ + @Column(name = "devuid", length = 64) + var devuid: String? = null + + /** + * 注册时间 + * */ + @Column(name = "registerdate", length = 16) + var registerdate: String? = null + + /** + * 关联tb_person + * */ + @Column(name = "userid", length = 32) + var userid: String? = null + + /** + * 注册手机类型 + * */ + @Column(name = "registerplatform", length = 20) + var registerplatform: String? = null + + /** + * 最后登录时间 + * */ + @Column(name = "lastlogin", length = 16) + var lastlogin: String? = null + + /** + * 最后登录手机类型 + * */ + @Column(name = "lastloginplatform", length = 20) + var lastloginplatform: String? = null + + /** + * 状态 + * */ + @Column(name = "status", length = 16) + var status: String? = null + + /** + * 登录密码 + * */ + @Column(name = "loginpwd", length = 64) + var loginpwd: String = "" + + /** + * 支付密码 + * */ + @Column(name = "paypwd", length = 64) + var paypwd: String? = null + + /** + * 登录密码错误次数 + * */ + @Column(name = "loginpwderror", length = 4) + var loginpwderror: Int = 0 + + /** + * 登录密码错误时间 + * */ + @Column(name = "loginpwderrortime", length = 16) + var loginpwderrortime: Long? = 0 + + /** + * 支付密码错误次数 + * */ + @Column(name = "paypwderror", length = 4) + var paypwderror: Int = 0 + + /** + * 支付密码错误时间 + * */ + @Column(name = "paypwderrortime", length = 16) + var paypwderrortime: Long? = 0 + + + /** + * jti + * */ + @Column(name = "jti", length = 64) + var jti: String? = null + +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/exception/UserLoginFailException.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/exception/UserLoginFailException.kt new file mode 100644 index 00000000..67d62430 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/exception/UserLoginFailException.kt @@ -0,0 +1,7 @@ +package com.supwisdom.dlpay.mobile.exception + +import org.springframework.security.core.AuthenticationException + +class UserLoginFailException(msg: String) : AuthenticationException(msg) { + private val serialVersionUID = 1170189980006964105L +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileApiService.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileApiService.kt new file mode 100644 index 00000000..c01e4305 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileApiService.kt @@ -0,0 +1,9 @@ +package com.supwisdom.dlpay.mobile.service + +import com.supwisdom.dlpay.mobile.domain.TBMobileUser + +interface MobileApiService { + fun saveUser(user: TBMobileUser): TBMobileUser + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileUserService.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileUserService.kt new file mode 100644 index 00000000..6d10c466 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/MobileUserService.kt @@ -0,0 +1,5 @@ +package com.supwisdom.dlpay.mobile.service + +import org.springframework.security.core.userdetails.UserDetailsService + +interface MobileUserService : UserDetailsService \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileApiServiceImpl.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileApiServiceImpl.kt new file mode 100644 index 00000000..fec5155e --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileApiServiceImpl.kt @@ -0,0 +1,19 @@ +package com.supwisdom.dlpay.mobile.service.impl + +import com.supwisdom.dlpay.framework.util.DateUtil +import com.supwisdom.dlpay.mobile.dao.MobileUserDao +import com.supwisdom.dlpay.mobile.domain.TBMobileUser +import com.supwisdom.dlpay.mobile.service.MobileApiService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class MobileApiServiceImpl : MobileApiService { + @Autowired + lateinit var mobileUserDao: MobileUserDao + + override fun saveUser(user: TBMobileUser): TBMobileUser { + user.lastlogin = DateUtil.getNow() + return mobileUserDao.save(user) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileUserServiceImpl.kt b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileUserServiceImpl.kt new file mode 100644 index 00000000..9f163348 --- /dev/null +++ b/src/main/kotlin/com/supwisdom/dlpay/mobile/service/impl/MobileUserServiceImpl.kt @@ -0,0 +1,37 @@ +package com.supwisdom.dlpay.mobile.service.impl + +import com.supwisdom.dlpay.mobile.dao.MobileUserDao +import com.supwisdom.dlpay.mobile.domain.TBMobileUser +import com.supwisdom.dlpay.mobile.exception.UserLoginFailException +import com.supwisdom.dlpay.mobile.service.MobileUserService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.AuthorityUtils +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Service + +@Service +class MobileUserServiceImpl : MobileUserService { + @Autowired + lateinit var mobileUserDao: MobileUserDao + + override fun loadUserByUsername(username: String?): UserDetails { + var temp = mobileUserDao.findByPhone(username!!) + if(temp!=null) { + if (temp.loginpwderror != null && temp.loginpwderror!! >= 3 && (System.currentTimeMillis() - temp.loginpwderrortime!!) < 1000 * 60 * 30) { + throw UserLoginFailException("密码错误次数过多,请稍后再试") + } else if (temp.loginpwderror != null && temp.loginpwderror!! >= 3 && (System.currentTimeMillis() - temp.loginpwderrortime!!) > 1000 * 60 * 30) { + //更新时间 + temp.loginpwderror = 0 + temp.loginpwderrortime = null + mobileUserDao.save(temp) + } + var authorities: Collection = AuthorityUtils.createAuthorityList("ROLE_USER") + temp.auths = authorities + }else{ + throw UsernameNotFoundException("用户不存在") + } + return temp + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt index 514b80c4..0914da62 100644 --- a/src/main/kotlin/com/supwisdom/dlpay/security.kt +++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt @@ -1,13 +1,18 @@ package com.supwisdom.dlpay +import com.supwisdom.dlpay.api.bean.JsonResult import com.supwisdom.dlpay.framework.core.JwtConfig import com.supwisdom.dlpay.framework.core.JwtTokenUtil import com.supwisdom.dlpay.framework.core.PasswordBCryptConfig import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository +import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler import com.supwisdom.dlpay.framework.security.MyPermissionEvaluator import com.supwisdom.dlpay.framework.security.ValidateCodeSecurityConfig import com.supwisdom.dlpay.framework.service.OperatorDetailService import com.supwisdom.dlpay.framework.util.TradeDict +import com.supwisdom.dlpay.mobile.AuthLoginFailHandler +import com.supwisdom.dlpay.mobile.AuthLoginSuccessHandler +import com.supwisdom.dlpay.mobile.service.MobileUserService import com.supwisdom.dlpay.system.common.DictPool import org.jose4j.jwt.consumer.InvalidJwtException import org.jose4j.lang.JoseException @@ -84,7 +89,7 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { url = url.replace(context,"") } logger.info(url) - if(!url.startsWith("/api/")){ + if(!url.startsWith("/api/")&&!url.startsWith("/mobileapi/")){ filterChain.doFilter(request, response) return } @@ -101,6 +106,11 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { return } val claims = getUtil().verifyToken(jwt) + if(url.equals("/mobileapi/logout")){ + SecurityContextHolder.clearContext() + apiJwtRepository.deleteById(claims["jti"].toString()) + throw JoseException("JWT has not been register") + } apiJwtRepository.findById(claims["jti"].toString()).let { if (!it.isPresent) { throw JoseException("JWT has not been register") @@ -119,14 +129,15 @@ class ApiJwtAuthenticationFilter : OncePerRequestFilter() { if (e.hasExpired()) { // jwt 过期后返回 401 apiJwtRepository.deleteById(e.jwtContext.jwtClaims.jwtId) - response.sendError(HttpStatus.UNAUTHORIZED.value(), e.message) - } else { - response.sendError(HttpStatus.BAD_REQUEST.value(), e.message) } + response.setStatus(HttpStatus.UNAUTHORIZED.value(), e.message) + return } catch (e: JoseException) { SecurityContextHolder.clearContext() // jwt 失效后返回 401 - response.sendError(HttpStatus.UNAUTHORIZED.value(), e.message) + response.setStatus(HttpStatus.UNAUTHORIZED.value(), e.message) + response.contentType = "application/json;charset=UTF-8" + return } } filterChain.doFilter(request, response) @@ -171,6 +182,60 @@ class WebSecurityConfig { return super.authenticationManagerBean() } } + @Configuration + @Order(2) + class MobileApiSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() { + @Autowired + lateinit var failureHandler: AuthLoginFailHandler + @Autowired + lateinit var successHandler: AuthLoginSuccessHandler + @Autowired + lateinit var passwordBCryptConfig: PasswordBCryptConfig + + @Autowired + lateinit var userDetailsService: MobileUserService + + @Autowired + lateinit var apiFilter: ApiJwtAuthenticationFilter + + override fun configure(auth: AuthenticationManagerBuilder) { + auth.authenticationProvider(userProvider()) + } + @Bean + fun userProvider(): DaoAuthenticationProvider { + return DaoAuthenticationProvider().apply { + setUserDetailsService(userDetailsService) + setPasswordEncoder(userPasswordEncoder()) + } + } + + @Bean + fun userPasswordEncoder(): BCryptPasswordEncoder { + return if (passwordBCryptConfig.seed.isBlank()) { + BCryptPasswordEncoder() + } else { + BCryptPasswordEncoder(passwordBCryptConfig.length, + SecureRandom(passwordBCryptConfig.seed.toByteArray())) + } + } + + override fun configure(http: HttpSecurity) { + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .antMatcher("/mobileapi/**") + .addFilterAfter(apiFilter, + UsernamePasswordAuthenticationFilter::class.java) + .authorizeRequests().anyRequest().authenticated() + .and() + .formLogin() + .loginProcessingUrl("/mobileapi/login") + .failureHandler(failureHandler) + .successHandler(successHandler) + .and().csrf().disable() + .sessionManagement().maximumSessions(1) + .expiredUrl("/mobileapi/sessionexpired") + } + } @Configuration class MvcWebSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() { @@ -179,7 +244,7 @@ class WebSecurityConfig { @Autowired lateinit var validateCodeSecurityConfig: ValidateCodeSecurityConfig @Autowired - lateinit var authenticationFailureHandler: AuthenticationFailureHandler + lateinit var authenticationFailureHandler: MyAuthenticationFailureHandler @Autowired lateinit var passwordBCryptConfig: PasswordBCryptConfig @@ -220,7 +285,7 @@ class WebSecurityConfig { http.apply(validateCodeSecurityConfig) .and() .authorizeRequests() - .antMatchers("/login", "/login/form").permitAll() + .antMatchers("/login", "/login/form","/mobileapi/**").permitAll() .antMatchers("/static/**").permitAll() .antMatchers("/code/image").permitAll() .antMatchers("/**").hasAnyRole("USER", "ADMIN") -- 2.17.1