package com.njcn.auth.controller; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.njcn.auth.service.UserTokenService; import com.njcn.common.pojo.annotation.OperateInfo; import com.njcn.common.pojo.constant.OperateType; import com.njcn.common.pojo.constant.SecurityConstants; import com.njcn.common.pojo.dto.UserTokenInfo; import com.njcn.common.pojo.enums.common.LogEnum; import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.response.HttpResult; import com.njcn.common.utils.HttpResultUtil; import com.njcn.common.utils.LogUtil; import com.njcn.common.utils.sm.DesUtils; import com.njcn.redis.utils.RedisUtil; import com.njcn.user.api.UserFeignClient; import com.njcn.web.controller.BaseController; import com.njcn.web.utils.RequestUtil; import com.njcn.web.utils.RestTemplateUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.*; import org.springframework.web.util.UriComponentsBuilder; import springfox.documentation.annotations.ApiIgnore; import java.net.URI; import java.security.KeyPair; import java.security.Principal; import java.security.interfaces.RSAPublicKey; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.*; /** * @author hongawen */ @Api(tags = "认证中心") @Slf4j @RestController @RequestMapping("/oauth") @AllArgsConstructor public class AuthController extends BaseController { private final TokenEndpoint tokenEndpoint; private final KeyPair keyPair; private final RedisUtil redisUtil; private final UserFeignClient userFeignClient; private final UserTokenService userTokenService; @ApiIgnore @OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.AUTHENTICATE) @ApiOperation("登录认证") @ApiImplicitParams({ @ApiImplicitParam(name = SecurityConstants.GRANT_TYPE, defaultValue = "password", value = "授权模式", required = true), @ApiImplicitParam(name = SecurityConstants.CLIENT_ID, defaultValue = "njcn", value = "Oauth2客户端ID", required = true), @ApiImplicitParam(name = SecurityConstants.CLIENT_SECRET, defaultValue = "njcnpqs", value = "Oauth2客户端秘钥", required = true), @ApiImplicitParam(name = SecurityConstants.REFRESH_TOKEN, value = "刷新token"), @ApiImplicitParam(name = SecurityConstants.USERNAME, value = "登录用户名"), @ApiImplicitParam(name = SecurityConstants.PASSWORD, value = "登录密码"), @ApiImplicitParam(name = SecurityConstants.IMAGE_CODE, value = "图形验证码"), @ApiImplicitParam(name = SecurityConstants.PHONE, value = "手机号"), @ApiImplicitParam(name = SecurityConstants.SMS_CODE, value = "短信验证码"), }) @PostMapping("/token") public Object postAccessToken(@ApiIgnore Principal principal, @RequestParam @ApiIgnore Map parameters) throws HttpRequestMethodNotSupportedException { String methodDescribe = getMethodDescribe("postAccessToken"); String username = parameters.get(SecurityConstants.USERNAME); String grantType = parameters.get(SecurityConstants.GRANT_TYPE); if (grantType.equalsIgnoreCase(SecurityConstants.GRANT_CAPTCHA)) { username = DesUtils.aesDecrypt(username); } else if (grantType.equalsIgnoreCase(SecurityConstants.GRANT_SMS_CODE)) { //短信方式登录,将手机号赋值为用户名 username = parameters.get(SecurityConstants.PHONE); } if (grantType.equalsIgnoreCase(SecurityConstants.REFRESH_TOKEN_KEY)) { //如果是刷新token,需要去黑名单校验 userTokenService.judgeRefreshToken(parameters.get(SecurityConstants.REFRESH_TOKEN_KEY)); } RequestUtil.saveLoginName(username); OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody(); //用户的登录名&密码校验成功后,判断当前该用户是否可以正常使用系统 if (!grantType.equalsIgnoreCase(SecurityConstants.GRANT_SMS_CODE)) { userFeignClient.judgeUserStatus(username); } //登录成功后,记录token信息,并处理踢人效果 userTokenService.recordUserInfo(oAuth2AccessToken, RequestUtil.getRealIp()); if (!grantType.equalsIgnoreCase(SecurityConstants.PASSWORD)) { return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, oAuth2AccessToken, methodDescribe); } else { return oAuth2AccessToken; } } @ApiOperation("用户登出系统") @DeleteMapping("/logout") public HttpResult logout() { String methodDescribe = getMethodDescribe("logout"); String userIndex = RequestUtil.getUserIndex(); String username = RequestUtil.getUsername(); LogUtil.njcnDebug(log, "{},用户名为:{}", methodDescribe, username); String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex; String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX + userIndex; Object onlineTokenInfoOld = redisUtil.getObjectByKey(onlineUserKey); List blackUsers = (List) redisUtil.getObjectByKey(blackUserKey); UserTokenInfo userTokenInfo; if (!Objects.isNull(onlineTokenInfoOld)) { //清除在线token信息 redisUtil.delete(onlineUserKey); userTokenInfo = (UserTokenInfo) onlineTokenInfoOld; if (CollectionUtils.isEmpty(blackUsers)) { blackUsers = new ArrayList<>(); } blackUsers.add(userTokenInfo); LocalDateTime refreshTokenExpire = userTokenInfo.getRefreshTokenExpire(); long lifeTime = Math.abs(refreshTokenExpire.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"))); redisUtil.saveByKeyWithExpire(blackUserKey, blackUsers, lifeTime); } return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); } /** * 文档隐藏该接口 */ @ApiIgnore @ApiOperation("RSA公钥获取接口") @GetMapping("/getPublicKey") public Map getPublicKey() { RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAKey key = new RSAKey.Builder(publicKey).build(); return new JWKSet(key).toJSONObject(); } /** * 自动登录 */ @OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.AUTHENTICATE) @ApiOperation("自动登录") @PostMapping("/autoLogin") @ApiImplicitParam(name = "phone", value = "手机号", required = true, paramType = "query") @ApiIgnore public HttpResult autoLogin(@RequestParam String phone) { String methodDescribe = getMethodDescribe("autoLogin"); String userUrl = "http://127.0.0.1:10214/oauth/token"; UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(userUrl) .queryParam("grant_type", "sms_code") .queryParam("client_id", "njcnapp") .queryParam("client_secret", "njcnpqs") .queryParam("phone", phone) .queryParam("smsCode", "123456789"); URI uri = builder.build().encode().toUri(); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, Objects.requireNonNull(RestTemplateUtil.post(uri, HttpResult.class).getBody()).getData(), methodDescribe); } }