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);
|
}
|
}
|
}
|
}
|