| package com.mzl.flower.web.login; | 
|   | 
| import cn.hutool.core.util.StrUtil; | 
| import com.mzl.flower.base.BaseController; | 
| import com.mzl.flower.base.R; | 
| import com.mzl.flower.base.ReturnDataDTO; | 
| import com.mzl.flower.base.cache.StringCacheClient; | 
| import com.mzl.flower.config.exception.BaseException; | 
| import com.mzl.flower.config.exception.ValidationException; | 
| import com.mzl.flower.config.security.SecurityUtils; | 
| import com.mzl.flower.config.security.token.AdminAuthenticationToken; | 
| import com.mzl.flower.config.security.token.PhoneAuthenticationToken; | 
| import com.mzl.flower.config.security.token.UserIdAuthenticationToken; | 
| import com.mzl.flower.constant.Constants; | 
| import com.mzl.flower.dto.request.RefreshTokenDto; | 
| import com.mzl.flower.dto.request.UserLoginDTO; | 
| import com.mzl.flower.dto.security.UserDTO; | 
| import com.mzl.flower.entity.system.User; | 
| import com.mzl.flower.service.login.LoginService; | 
| import com.mzl.flower.service.system.UserService; | 
| import com.wf.captcha.GifCaptcha; | 
| import com.wf.captcha.utils.CaptchaUtil; | 
| import io.swagger.annotations.Api; | 
| import io.swagger.annotations.ApiOperation; | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.apache.commons.lang3.StringUtils; | 
| import org.springframework.beans.factory.annotation.Autowired; | 
| import org.springframework.http.HttpHeaders; | 
| import org.springframework.http.ResponseEntity; | 
| import org.springframework.security.authentication.AuthenticationDetailsSource; | 
| import org.springframework.security.authentication.AuthenticationManager; | 
| import org.springframework.security.authentication.BadCredentialsException; | 
| import org.springframework.security.core.Authentication; | 
| import org.springframework.security.core.userdetails.UsernameNotFoundException; | 
| import org.springframework.security.oauth2.common.OAuth2AccessToken; | 
| import org.springframework.security.oauth2.common.OAuth2RefreshToken; | 
| import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; | 
| import org.springframework.security.oauth2.provider.OAuth2Authentication; | 
| import org.springframework.security.oauth2.provider.token.TokenStore; | 
| import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | 
| import org.springframework.web.bind.annotation.*; | 
|   | 
| import javax.servlet.http.HttpServletRequest; | 
| import javax.servlet.http.HttpServletResponse; | 
|   | 
| @Slf4j | 
| @RestController | 
| @RequestMapping("/api") | 
| @Api(value = "运营平台-登录", tags = "登录-登录") | 
| public class LoginController extends BaseController { | 
|   | 
|     private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource(); | 
|   | 
|     @Autowired | 
|     private AuthenticationManager authenticationManager; | 
|   | 
|     @Autowired | 
|     private TokenStore tokenStore; | 
|   | 
|     @Autowired | 
|     private LoginService loginService; | 
|   | 
|     @Autowired | 
|     private StringCacheClient stringCacheClient; | 
|   | 
|     @Autowired | 
|     private UserService userService; | 
|   | 
|     public static final String SMS_CODE_KEY = "SMS-CODE-KEY"; | 
|     public static final String TOKEN_KEY = "TOKEN-KEY"; | 
|   | 
|     public static final String SEPARATOR = ":"; | 
|   | 
|     @PostMapping("/login/admin") | 
|     @ApiOperation(value = "管理员登录", notes = "管理员登录") | 
|     public ResponseEntity<ReturnDataDTO<OAuth2AccessToken>> login(HttpServletRequest request | 
|             , @RequestBody UserLoginDTO loginDTO) { | 
|         checkCaptchaCode(loginDTO.getCodeId(), loginDTO.getCode()); | 
|   | 
|         String username = loginDTO.getUsername(); | 
|         String password = loginDTO.getPassword(); | 
|   | 
|         if (StringUtils.isBlank(username)) { | 
|             throw new ValidationException("用户名不能为空"); | 
|         } | 
|         if (StringUtils.isBlank(password)) { | 
|             throw new ValidationException("密码不能为空"); | 
|         } | 
|         User user = userService.findByTel(username, Constants.USER_TYPE.admin.name()); | 
|         if(user == null){ | 
|             throw new ValidationException("用户不存在"); | 
|         } | 
|         String tokenCache = stringCacheClient.get(TOKEN_KEY + SEPARATOR + user.getId()); | 
|         if (StringUtils.isNotBlank(tokenCache))  { | 
|             //强制删除token,下线 | 
|             removeToken(tokenCache,user.getId()); | 
|         } | 
|         try { | 
|             AdminAuthenticationToken authRequest = new AdminAuthenticationToken(username, password); | 
|             authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); | 
|             Authentication authentication = authenticationManager.authenticate(authRequest); | 
|             OAuth2AccessToken token = loginService.getAccessToken(authentication,Constants.USER_TYPE.admin.name()); | 
|             stringCacheClient.set(TOKEN_KEY + SEPARATOR + user.getId(),token.getValue()); | 
|             return returnData(R.SUCCESS.getCode(),token); | 
|         }catch (BadCredentialsException e){ | 
|             throw new ValidationException("用户名或密码错误"); | 
|         }catch (UsernameNotFoundException e){ | 
|             throw new ValidationException("用户不存在"); | 
|         }catch (Exception e) { | 
|             log.error(e.getMessage(), e); | 
|             throw new BaseException(R.RUNTIME_EXCEPTION.getCode(),"登录错误"); | 
|         } | 
|     } | 
|     @PostMapping("/login/admin/wx") | 
|     @ApiOperation(value = "微信端-登录", notes = "微信端-登录") | 
|     public ResponseEntity<ReturnDataDTO<OAuth2AccessToken>> loginWxAdmin(HttpServletRequest request | 
|             , @RequestHeader(value = "clientType", required = false) String clientType | 
|             , @RequestBody UserLoginDTO loginDTO) { | 
|         String username = loginDTO.getUsername(); | 
|         String password = loginDTO.getPassword(); | 
|   | 
|         if (StringUtils.isBlank(username)) { | 
|             throw new ValidationException("用户名不能为空"); | 
|         } | 
|         if (StringUtils.isBlank(password)) { | 
|             throw new ValidationException("密码不能为空"); | 
|         } | 
|         User user = userService.findByTel(username, Constants.USER_TYPE.admin.name()); | 
|         if(user == null){ | 
|             throw new ValidationException("用户不存在"); | 
|         } | 
|         String tokenCache = stringCacheClient.get(TOKEN_KEY + SEPARATOR + user.getId()); | 
|         if (StringUtils.isNotBlank(tokenCache))  { | 
|             //强制删除token,下线 | 
|             removeToken(tokenCache,user.getId()); | 
|         } | 
|         try { | 
|             AdminAuthenticationToken authRequest = new AdminAuthenticationToken(username, password); | 
|             authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); | 
|             Authentication authentication = authenticationManager.authenticate(authRequest); | 
|             OAuth2AccessToken token = loginService.getAccessToken(authentication,Constants.USER_TYPE.admin.name()); | 
|             stringCacheClient.set(TOKEN_KEY + SEPARATOR + user.getId(),token.getValue()); | 
|             return returnData(R.SUCCESS.getCode(),token); | 
|         }catch (BadCredentialsException e){ | 
|             throw new ValidationException("用户名或密码错误"); | 
|         }catch (UsernameNotFoundException e){ | 
|             throw new ValidationException("用户不存在"); | 
|         }catch (Exception e) { | 
|             log.error(e.getMessage(), e); | 
|             throw new BaseException(R.RUNTIME_EXCEPTION.getCode(),"登录错误"); | 
|         } | 
|     } | 
|   | 
|   | 
|     @PostMapping("/login/admin/phone") | 
|     @ApiOperation(value = "手机验证码登录系统", notes = "手机验证码登录系统") | 
|     public ResponseEntity<ReturnDataDTO<OAuth2AccessToken>>  loginPhone(HttpServletRequest request, | 
|                                                                         @RequestBody UserLoginDTO loginDTO) { | 
|         String tel = loginDTO.getUsername(); | 
|         String smsCode = loginDTO.getSmsCode(); | 
|         if (StringUtils.isBlank(tel)) { | 
|             throw new ValidationException("手机号码不能为空"); | 
|         } | 
|         if (StringUtils.isBlank(smsCode)) { | 
|             throw new ValidationException("手机验证码不能为空"); | 
|         } | 
|         //从缓存中获取验证码 | 
|         String smsCacheCode = stringCacheClient.get(SMS_CODE_KEY + SEPARATOR + Constants.USER_TYPE.admin.name() + SEPARATOR + tel); | 
|         if (!StringUtils.equals(smsCode, smsCacheCode)) { | 
|             throw new ValidationException("手机验证码不正确"); | 
|         } | 
|         User user = userService.findByTel(tel, Constants.USER_TYPE.admin.name()); | 
|         if(user == null){ | 
|             throw new ValidationException("用户不存在"); | 
|         } | 
|         String tokenCache = stringCacheClient.get(TOKEN_KEY + SEPARATOR + user.getId()); | 
|         if (StringUtils.isNotBlank(tokenCache))  { | 
|             //强制删除token,下线 | 
|             removeToken(tokenCache,user.getId()); | 
|         } | 
|         try { | 
|             PhoneAuthenticationToken authRequest = new PhoneAuthenticationToken(tel, smsCode, Constants.USER_TYPE.admin.name()); | 
|             authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); | 
|             Authentication authentication = authenticationManager.authenticate(authRequest); | 
|             OAuth2AccessToken token = loginService.getAccessToken(authentication, Constants.USER_TYPE.admin.name()); | 
|             //删除缓存中的验证码 | 
|             stringCacheClient.delete(SMS_CODE_KEY + SEPARATOR + Constants.USER_TYPE.admin.name() + SEPARATOR + tel); | 
|             stringCacheClient.set(TOKEN_KEY + SEPARATOR + user.getId(),token.getValue()); | 
|             return returnData(R.SUCCESS.getCode(),token); | 
|         }catch (UsernameNotFoundException e){ | 
|             throw new ValidationException("用户不存在"); | 
|         }catch (Exception e) { | 
|             log.error(e.getMessage(), e); | 
|             throw new BaseException(R.RUNTIME_EXCEPTION.getCode(),"登录错误"); | 
|         } | 
|     } | 
|   | 
|   | 
|   | 
|     @PostMapping("/logout") | 
|     @ApiOperation(value = "登出系统", notes = "登出系统") | 
|     public ResponseEntity<ReturnDataDTO> logout( | 
|             @RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String token) { | 
|         String userId = SecurityUtils.getUserId(); | 
|         if (StringUtils.isNotBlank(token)) { | 
|             stringCacheClient.delete(TOKEN_KEY + SEPARATOR + userId); | 
|             String tokenValue = token.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim(); | 
|             OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue); | 
|             if (accessToken != null && StringUtils.isNotBlank(accessToken.getValue())) { | 
|                 tokenStore.removeAccessToken(accessToken); | 
|                 OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); | 
|                 tokenStore.removeRefreshToken(refreshToken); | 
|             } | 
|         } | 
|         return returnData(R.SUCCESS.getCode(), null); | 
|     } | 
|   | 
|     @PostMapping("/refresh-token") | 
|     @ApiOperation(value = "刷新token", notes = "刷新token") | 
|     public ResponseEntity<ReturnDataDTO> refreshToken(HttpServletRequest request | 
|             , @RequestHeader(value = "clientType", required = false) String clientType | 
|             , @RequestBody RefreshTokenDto dto) { | 
|         OAuth2AccessToken token = null; | 
|         try { | 
|             String refreshTokenValue = dto.getRefreshToken(); | 
|             OAuth2RefreshToken refreshToken = this.tokenStore.readRefreshToken(refreshTokenValue); | 
|             if (refreshToken == null) { | 
|                 throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue); | 
|             } else { | 
|                 OAuth2Authentication authentication = this.tokenStore.readAuthenticationForRefreshToken(refreshToken); | 
|                 UserDTO p = (UserDTO)authentication.getPrincipal(); | 
|                 UserIdAuthenticationToken authRequest = new UserIdAuthenticationToken(p.getId(), p.getId()); | 
|                 authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); | 
|                 Authentication a = authenticationManager.authenticate(authRequest); | 
|                 token = loginService.getAccessToken(a, clientType); | 
|             } | 
|         } catch (InvalidGrantException e) { | 
|             throw new ValidationException("用户登录信息过期,请重新登录"); | 
|         } | 
|   | 
|         return returnData(R.SUCCESS.getCode(), token); | 
|     } | 
|   | 
|     @PostMapping("/token-check") | 
|     @ApiOperation(value = "token验证是否过期", notes = "token验证是否过期") | 
|     public ResponseEntity<ReturnDataDTO> checkToken() { | 
|         return returnData(R.SUCCESS.getCode(), null); | 
|     } | 
|   | 
|     @GetMapping("/pub/captcha/{uuid}") | 
|     public void captcha(HttpServletRequest request, HttpServletResponse response | 
|             , @PathVariable("uuid") String uuid) throws Exception{ | 
|         // 设置请求头为输出图片类型 | 
|         response.setContentType("image/gif"); | 
|         response.setHeader("Pragma", "No-cache"); | 
|         response.setHeader("Cache-Control", "no-cache"); | 
|         response.setDateHeader("Expires", 0); | 
|         GifCaptcha gifCaptcha = new GifCaptcha(130,48,4); | 
|         gifCaptcha.out(response.getOutputStream()); | 
|         String verCode = gifCaptcha.text().toLowerCase(); | 
|         log.info(verCode); | 
|         stringCacheClient.set(captchaKey(uuid), verCode, 2*60); | 
|     } | 
|   | 
|     private String captchaKey(String uuid){ | 
|         return "captcha_" + uuid; | 
|     } | 
|   | 
|     private void checkCaptchaCode(String uuid, String code){ | 
|         if(StringUtils.isEmpty(code)){ | 
|             throw new ValidationException("验证码不能为空"); | 
|         } | 
|   | 
|         String key = captchaKey(uuid); | 
|         String codeInCache = stringCacheClient.get(key); | 
|         stringCacheClient.delete(key); | 
|   | 
|         if(StringUtils.isEmpty(codeInCache) || !codeInCache.equalsIgnoreCase(code)){ | 
|             throw new ValidationException("无效验证码"); | 
|         } | 
|     } | 
|   | 
|     public void removeToken(String token,String userId) { | 
|         if (StringUtils.isNotBlank(token) && StringUtils.isNotBlank(userId))  { | 
|             stringCacheClient.delete(TOKEN_KEY + SEPARATOR + userId); | 
|             String tokenValue = token.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim(); | 
|             OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue); | 
|             if (accessToken != null && StringUtils.isNotBlank(accessToken.getValue())) { | 
|                 tokenStore.removeAccessToken(accessToken); | 
|                 OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); | 
|                 tokenStore.removeRefreshToken(refreshToken); | 
|             } | 
|         } | 
|     } | 
| } |