Commit 96567d4d by 段启岩

refresh_token完成

parent 8923ddab
...@@ -2,6 +2,7 @@ package cn.meteor.beyondclouds.core.authentication; ...@@ -2,6 +2,7 @@ package cn.meteor.beyondclouds.core.authentication;
import cn.meteor.beyondclouds.core.constant.SysConstants; import cn.meteor.beyondclouds.core.constant.SysConstants;
import cn.meteor.beyondclouds.core.emuns.SubjectType; import cn.meteor.beyondclouds.core.emuns.SubjectType;
import cn.meteor.beyondclouds.modules.user.enums.ClientType;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -22,6 +23,11 @@ public class Subject implements Serializable { ...@@ -22,6 +23,11 @@ public class Subject implements Serializable {
private Serializable id; private Serializable id;
/** /**
* 客户端类型
*/
private ClientType clientType;
/**
* 访问者IP地址 * 访问者IP地址
*/ */
private String ipAddress; private String ipAddress;
...@@ -31,23 +37,24 @@ public class Subject implements Serializable { ...@@ -31,23 +37,24 @@ public class Subject implements Serializable {
*/ */
private SubjectType type; private SubjectType type;
private Subject(Serializable id, SubjectType type, String ipAddress) { private Subject(Serializable id, ClientType clientType, SubjectType type, String ipAddress) {
this.id = id; this.id = id;
this.type = type; this.type = type;
this.ipAddress = ipAddress; this.ipAddress = ipAddress;
this.clientType = clientType;
} }
public static Subject anonymous(String ipAddress) { public static Subject anonymous(String ipAddress) {
return new Subject(null, SubjectType.ANONYMOUS, ipAddress); return new Subject(null, null, SubjectType.ANONYMOUS, ipAddress);
} }
public static Subject anonymous() { public static Subject anonymous() {
return new Subject(SysConstants.SYS_ID, SubjectType.ANONYMOUS, SysConstants.SYS_ID); return new Subject(SysConstants.SYS_ID, null, SubjectType.ANONYMOUS, SysConstants.SYS_ID);
} }
public static Subject authenticated(Serializable id, String ipAddress) { public static Subject authenticated(Serializable id, Integer clientType, String ipAddress) {
return new Subject(id, SubjectType.AUTHENTICATED, ipAddress); return new Subject(id, ClientType.valueOf(clientType), SubjectType.AUTHENTICATED, ipAddress);
} }
/** /**
......
...@@ -26,7 +26,12 @@ public enum AuthorizationErrorCode implements IErrorCode { ...@@ -26,7 +26,12 @@ public enum AuthorizationErrorCode implements IErrorCode {
/** /**
* token验证失败 * token验证失败
*/ */
SIGN_VERIFY_FAILURE(1003, "token验证失败"); SIGN_VERIFY_FAILURE(1003, "token验证失败"),
/**
* token验证失败
*/
REFRESH_TOKEN_VERIFY_FAILURE(1004, "refresh_token验证失败");
private long code; private long code;
private String msg; private String msg;
......
...@@ -6,6 +6,7 @@ import cn.meteor.beyondclouds.core.constant.SysConstants; ...@@ -6,6 +6,7 @@ import cn.meteor.beyondclouds.core.constant.SysConstants;
import cn.meteor.beyondclouds.core.emuns.AuthorizationErrorCode; import cn.meteor.beyondclouds.core.emuns.AuthorizationErrorCode;
import cn.meteor.beyondclouds.core.exception.AuthorizationException; import cn.meteor.beyondclouds.core.exception.AuthorizationException;
import cn.meteor.beyondclouds.core.redis.TokenManager; import cn.meteor.beyondclouds.core.redis.TokenManager;
import cn.meteor.beyondclouds.modules.user.dto.TokenInfo;
import cn.meteor.beyondclouds.util.RequestUtils; import cn.meteor.beyondclouds.util.RequestUtils;
import cn.meteor.beyondclouds.util.ThreadLocalMap; import cn.meteor.beyondclouds.util.ThreadLocalMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -57,12 +58,12 @@ public class TokenInterceptor implements HandlerInterceptor { ...@@ -57,12 +58,12 @@ public class TokenInterceptor implements HandlerInterceptor {
try { try {
// 获取token // 获取token
String token = authorization.substring(BEARER_AUTHORIZATION_START.length() + 1); String token = authorization.substring(BEARER_AUTHORIZATION_START.length() + 1);
String userId = tokenManager.getUserId(token); TokenInfo tokenInfo = tokenManager.getTokenInfo(token);
if (null == userId) { if (null == tokenInfo) {
throw new AuthorizationException(AuthorizationErrorCode.SIGN_VERIFY_FAILURE); throw new AuthorizationException(AuthorizationErrorCode.SIGN_VERIFY_FAILURE);
} }
// 构建一个经过系统认证的subject // 构建一个经过系统认证的subject
Subject authenticatedSubject = Subject.authenticated(userId, RequestUtils.getIpAddr(request)); Subject authenticatedSubject = Subject.authenticated(tokenInfo.getUserId(), tokenInfo.getClientType(), RequestUtils.getIpAddr(request));
ThreadLocalMap.put(SysConstants.HTTP_ATTRIBUTE_SUBJECT, authenticatedSubject); ThreadLocalMap.put(SysConstants.HTTP_ATTRIBUTE_SUBJECT, authenticatedSubject);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
......
...@@ -82,11 +82,19 @@ public final class RedisKey { ...@@ -82,11 +82,19 @@ public final class RedisKey {
return "USER_NICK_GEN:" + datePrefix; return "USER_NICK_GEN:" + datePrefix;
} }
public static String USER_TOKEN_INFO(String userId, String clientType) {
return "USER_TO_TOKEN:" + clientType + ":" + userId;
}
public static String TOKEN_TO_USER(String token) { public static String TOKEN_TO_USER(String token) {
return "TOKEN_TO_USER:" + token; return "TOKEN_TO_USER:" + token;
} }
public static String USER_TO_TOKEN(String userId) { public static String USER_REFRESH_TOKEN_INFO(String userId, String clientType) {
return "USER_TO_TOKEN:" + userId; return "USER_TO_REFRESH_TOKEN:" + clientType + ":" + userId;
}
public static String REFRESH_TOKEN_TO_USER(String token) {
return "REFRESH_TOKEN_TO_USER:" + token;
} }
} }
package cn.meteor.beyondclouds.core.redis; package cn.meteor.beyondclouds.core.redis;
import cn.meteor.beyondclouds.common.helper.IRedisHelper; import cn.meteor.beyondclouds.common.helper.IRedisHelper;
import cn.meteor.beyondclouds.modules.user.dto.TokenInfo;
import cn.meteor.beyondclouds.modules.user.dto.TokenResult;
import cn.meteor.beyondclouds.modules.user.enums.ClientType;
import cn.meteor.beyondclouds.util.UUIDUtils; import cn.meteor.beyondclouds.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.Serializable;
/** /**
* @author meteor * @author meteor
*/ */
...@@ -13,6 +18,13 @@ public class TokenManager { ...@@ -13,6 +18,13 @@ public class TokenManager {
private IRedisHelper redisHelper; private IRedisHelper redisHelper;
private static final int DEFAULT_EXPIRE = 60 * 60 * 2;
private static final int REFRESH_DEFAULT_EXPIRE = DEFAULT_EXPIRE * 2;
private static final int ANDROID_DEFAULT_EXPIRE = 60 * 60 * 24;
private static final int ANDROID_REFRESH_DEFAULT_EXPIRE = 60 * 60 * 24 * 10;
@Autowired @Autowired
public void setRedisHelper(IRedisHelper redisHelper) { public void setRedisHelper(IRedisHelper redisHelper) {
this.redisHelper = redisHelper; this.redisHelper = redisHelper;
...@@ -20,64 +32,105 @@ public class TokenManager { ...@@ -20,64 +32,105 @@ public class TokenManager {
/** /**
* 生成token * 生成token
*
* @param userId * @param userId
* @param clientType
* @return * @return
*/ */
public String generateToken(String userId, int expireSeconds) { public TokenResult generateToken(String userId, ClientType clientType) {
// 生成新token
String newToken = UUIDUtils.randomToken(); String newToken = UUIDUtils.randomToken();
String newRefreshToken = UUIDUtils.randomToken();
// 删除旧token // 如果不是web端,则删除旧token和refresh_token
String oldToken = redisHelper.get(RedisKey.USER_TO_TOKEN(userId)); removeTokenAndRefreshToken(userId, clientType);
if (oldToken != null) {
redisHelper.del( // 存储新token和新的refresh_token
RedisKey.TOKEN_TO_USER(oldToken), int tokenExpire, refreshTokenExpire;
RedisKey.USER_TO_TOKEN(userId) switch (clientType) {
);
case ANDROID:
tokenExpire = ANDROID_DEFAULT_EXPIRE;
refreshTokenExpire = ANDROID_REFRESH_DEFAULT_EXPIRE;
break;
case WEB:
default:
tokenExpire = DEFAULT_EXPIRE;
refreshTokenExpire = REFRESH_DEFAULT_EXPIRE;
} }
// 存储新token redisHelper.set(RedisKey.TOKEN_TO_USER(newToken), TokenInfo.create(newToken, userId, clientType.getType()), tokenExpire);
redisHelper.set(RedisKey.TOKEN_TO_USER(newToken), userId, expireSeconds); redisHelper.set(RedisKey.USER_TOKEN_INFO(userId, clientType.name()), newToken, tokenExpire);
redisHelper.set(RedisKey.USER_TO_TOKEN(userId), newToken, expireSeconds);
return newToken; redisHelper.set(RedisKey.REFRESH_TOKEN_TO_USER(newRefreshToken), TokenInfo.create(newRefreshToken, userId, clientType.getType()), refreshTokenExpire);
redisHelper.set(RedisKey.USER_REFRESH_TOKEN_INFO(userId, clientType.name()), newRefreshToken, refreshTokenExpire);
return new TokenResult(newToken, newRefreshToken);
} }
/** /**
* 根据token获取用户ID * 根据token获取token信息
*
* @param token * @param token
* @return * @return
*/ */
public String getUserId(String token) { public TokenInfo getTokenInfo(String token) {
String userId = redisHelper.get(RedisKey.TOKEN_TO_USER(token)); TokenInfo tokenInfo = redisHelper.get(RedisKey.TOKEN_TO_USER(token), TokenInfo.class);
if (null != userId) {
// 如果是web端,则刷新token
if (null != tokenInfo && ClientType.valueOf(tokenInfo.getClientType()) == ClientType.WEB) {
// 刷新token过期时间 // 刷新token过期时间
redisHelper.expire(RedisKey.TOKEN_TO_USER(token), 60 * 120); redisHelper.expire(RedisKey.TOKEN_TO_USER(token), DEFAULT_EXPIRE);
redisHelper.expire(RedisKey.USER_TO_TOKEN(userId), 60 * 120); redisHelper.expire(RedisKey.USER_TOKEN_INFO(tokenInfo.getUserId(), ClientType.WEB.name()), DEFAULT_EXPIRE);
} }
return userId; return tokenInfo;
} }
/** /**
* 删除token * 根据refreshToken获取refreshToken信息
*
* @param refreshToken
* @return
*/
public TokenInfo getRefreshTokenInfo(String refreshToken) {
TokenInfo tokenInfo = redisHelper.get(RedisKey.REFRESH_TOKEN_TO_USER(refreshToken), TokenInfo.class);
return tokenInfo;
}
/**
* 删除token和refreshToken
*
* @param userId * @param userId
* @param clientType
*/ */
public void removeToken(String userId) { public void removeTokenAndRefreshToken(String userId, ClientType clientType) {
// 删除旧token // 删除旧token和refresh_token
String oldToken = redisHelper.get(RedisKey.USER_TO_TOKEN(userId)); String oldToken = redisHelper.get(RedisKey.USER_TOKEN_INFO(userId, clientType.name()));
if (oldToken != null) { String oldRefreshToken = redisHelper.get(RedisKey.USER_REFRESH_TOKEN_INFO(userId, clientType.name()));
if (null != oldToken) {
redisHelper.del( redisHelper.del(
RedisKey.TOKEN_TO_USER(oldToken), RedisKey.TOKEN_TO_USER(oldToken),
RedisKey.USER_TO_TOKEN(userId) RedisKey.USER_TOKEN_INFO(userId, clientType.name())
);
}
if (null != oldRefreshToken) {
redisHelper.del(
RedisKey.REFRESH_TOKEN_TO_USER(oldRefreshToken),
RedisKey.USER_REFRESH_TOKEN_INFO(userId, clientType.name())
); );
} }
} }
/** /**
* 判断用户是否登录 * 判断用户是否登录web端
* @param userId * @param userId
* @return * @return
*/ */
public boolean isLogin(String userId) { public boolean isLoginToWeb(String userId) {
return null != redisHelper.get(RedisKey.USER_TO_TOKEN(userId)); return null != redisHelper.get(RedisKey.USER_TOKEN_INFO(userId, ClientType.WEB.name()));
} }
} }
...@@ -17,11 +17,11 @@ public enum VersionErrorCode implements IErrorCode { ...@@ -17,11 +17,11 @@ public enum VersionErrorCode implements IErrorCode {
@Override @Override
public long code() { public long code() {
return 0; return code;
} }
@Override @Override
public String msg() { public String msg() {
return null; return msg;
} }
} }
package cn.meteor.beyondclouds.modules.im.server; package cn.meteor.beyondclouds.modules.im.server;
import cn.meteor.beyondclouds.core.redis.TokenManager; import cn.meteor.beyondclouds.core.redis.TokenManager;
import cn.meteor.beyondclouds.modules.user.dto.TokenInfo;
import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.protocol.Packet;
import com.corundumstudio.socketio.protocol.PacketType;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -77,14 +75,15 @@ public class SocketIOServiceImpl implements SocketIOService { ...@@ -77,14 +75,15 @@ public class SocketIOServiceImpl implements SocketIOService {
} }
// 校验token // 校验token
String userId = tokenManager.getUserId(token); TokenInfo tokenInfo = tokenManager.getTokenInfo(token);
if (null == userId) { if (null == tokenInfo) {
client.disconnect(); client.disconnect();
return; return;
} }
// 将session存入内存 // 将session存入内存
String userId = tokenInfo.getUserId();
putClient(userId, client); putClient(userId, client);
log.debug("user {} [{},{},{}] connected to the im server", userId, client.getSessionId(), client.getRemoteAddress(), client.getNamespace()); log.debug("user {} [{},{},{}] connected to the im server", userId, client.getSessionId(), client.getRemoteAddress(), client.getNamespace());
// client.sendEvent(PUSH_EVENT, "hello, 欢迎连接服务器!"); // client.sendEvent(PUSH_EVENT, "hello, 欢迎连接服务器!");
...@@ -95,9 +94,9 @@ public class SocketIOServiceImpl implements SocketIOService { ...@@ -95,9 +94,9 @@ public class SocketIOServiceImpl implements SocketIOService {
log.info("断开连接."); log.info("断开连接.");
String token = client.getHandshakeData().getSingleUrlParam("token"); String token = client.getHandshakeData().getSingleUrlParam("token");
if (null != token) { if (null != token) {
String userId = tokenManager.getUserId(token); TokenInfo tokenInfo = tokenManager.getTokenInfo(token);
if (null != userId) { if (null != tokenInfo) {
Set<SocketIOClient> clients = CLIENT_MAP.get(userId); Set<SocketIOClient> clients = CLIENT_MAP.get(tokenInfo.getUserId());
if (!CollectionUtils.isEmpty(clients)) { if (!CollectionUtils.isEmpty(clients)) {
log.debug("before remove{}", clients); log.debug("before remove{}", clients);
log.debug("remove{}", client); log.debug("remove{}", client);
......
package cn.meteor.beyondclouds.modules.message.listener; package cn.meteor.beyondclouds.modules.message.listener;
import cn.meteor.beyondclouds.core.authentication.Subject;
import cn.meteor.beyondclouds.core.constant.SysConstants; import cn.meteor.beyondclouds.core.constant.SysConstants;
import cn.meteor.beyondclouds.core.listener.DataItemChangeListener; import cn.meteor.beyondclouds.core.listener.DataItemChangeListener;
import cn.meteor.beyondclouds.core.queue.message.DataItemChangeMessage; import cn.meteor.beyondclouds.core.queue.message.DataItemChangeMessage;
...@@ -12,7 +11,6 @@ import cn.meteor.beyondclouds.modules.blog.entity.BlogPraise; ...@@ -12,7 +11,6 @@ import cn.meteor.beyondclouds.modules.blog.entity.BlogPraise;
import cn.meteor.beyondclouds.modules.blog.service.IBlogCommentService; import cn.meteor.beyondclouds.modules.blog.service.IBlogCommentService;
import cn.meteor.beyondclouds.modules.blog.service.IBlogPraiseService; import cn.meteor.beyondclouds.modules.blog.service.IBlogPraiseService;
import cn.meteor.beyondclouds.modules.blog.service.IBlogService; import cn.meteor.beyondclouds.modules.blog.service.IBlogService;
import cn.meteor.beyondclouds.modules.feedback.service.IFeedbackService;
import cn.meteor.beyondclouds.modules.im.server.SocketIOService; import cn.meteor.beyondclouds.modules.im.server.SocketIOService;
import cn.meteor.beyondclouds.modules.message.dto.MessageDTO; import cn.meteor.beyondclouds.modules.message.dto.MessageDTO;
import cn.meteor.beyondclouds.modules.message.entity.Message; import cn.meteor.beyondclouds.modules.message.entity.Message;
...@@ -40,8 +38,6 @@ import cn.meteor.beyondclouds.modules.user.entity.User; ...@@ -40,8 +38,6 @@ import cn.meteor.beyondclouds.modules.user.entity.User;
import cn.meteor.beyondclouds.modules.user.entity.UserFollow; import cn.meteor.beyondclouds.modules.user.entity.UserFollow;
import cn.meteor.beyondclouds.modules.user.service.IUserFollowService; import cn.meteor.beyondclouds.modules.user.service.IUserFollowService;
import cn.meteor.beyondclouds.modules.user.service.IUserService; import cn.meteor.beyondclouds.modules.user.service.IUserService;
import cn.meteor.beyondclouds.util.SubjectUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -470,7 +466,7 @@ public class MessageListener implements DataItemChangeListener { ...@@ -470,7 +466,7 @@ public class MessageListener implements DataItemChangeListener {
// 对消息长度进行收缩 // 对消息长度进行收缩
contractMsgContent(messageDTO); contractMsgContent(messageDTO);
if(tokenManager.isLogin(to)) { if(tokenManager.isLoginToWeb(to)) {
socketIOService.pushMessage(to, messageDTO); socketIOService.pushMessage(to, messageDTO);
} }
} }
......
...@@ -8,9 +8,11 @@ import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO; ...@@ -8,9 +8,11 @@ import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO;
import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO; import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO;
import cn.meteor.beyondclouds.modules.user.enums.AccountType; import cn.meteor.beyondclouds.modules.user.enums.AccountType;
import cn.meteor.beyondclouds.modules.user.enums.AuthType; import cn.meteor.beyondclouds.modules.user.enums.AuthType;
import cn.meteor.beyondclouds.modules.user.enums.ClientType;
import cn.meteor.beyondclouds.modules.user.exception.AuthenticationServiceException; import cn.meteor.beyondclouds.modules.user.exception.AuthenticationServiceException;
import cn.meteor.beyondclouds.modules.user.exception.UserServiceException; import cn.meteor.beyondclouds.modules.user.exception.UserServiceException;
import cn.meteor.beyondclouds.modules.user.form.LocalAuthFrom; import cn.meteor.beyondclouds.modules.user.form.LocalAuthFrom;
import cn.meteor.beyondclouds.modules.user.form.RefreshTokenFrom;
import cn.meteor.beyondclouds.modules.user.form.SmsAuthFrom; import cn.meteor.beyondclouds.modules.user.form.SmsAuthFrom;
import cn.meteor.beyondclouds.modules.user.service.IAuthenticationService; import cn.meteor.beyondclouds.modules.user.service.IAuthenticationService;
import cn.meteor.beyondclouds.modules.user.vo.UserAuthMapVO; import cn.meteor.beyondclouds.modules.user.vo.UserAuthMapVO;
...@@ -44,10 +46,18 @@ public class AuthenticationApi { ...@@ -44,10 +46,18 @@ public class AuthenticationApi {
@Anonymous @Anonymous
@ApiOperation(value = "账号密码认证") @ApiOperation(value = "账号密码认证")
@PostMapping("/password") @PostMapping("/password")
public Response<AuthenticationResultDTO> localAuth(@RequestBody @Valid LocalAuthFrom localAuthFrom) { public Response<?> localAuth(@RequestBody @Valid LocalAuthFrom localAuthFrom, BindingResult bindingResult,
@RequestParam(value = "clientType", required = false) Integer clientType) {
if (bindingResult.hasErrors()) {
return Response.fieldError(bindingResult.getFieldError());
}
AuthenticationResultDTO authenticationResult = null; AuthenticationResultDTO authenticationResult = null;
ClientType type = ClientType.valueOf(clientType);
try { try {
authenticationResult = authenticationService.localAuthentication(localAuthFrom.getAccount(), localAuthFrom.getPassword()); authenticationResult = authenticationService.localAuthentication(localAuthFrom.getAccount(), localAuthFrom.getPassword(), type);
return Response.success(authenticationResult); return Response.success(authenticationResult);
} catch (AuthenticationServiceException e) { } catch (AuthenticationServiceException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -58,14 +68,16 @@ public class AuthenticationApi { ...@@ -58,14 +68,16 @@ public class AuthenticationApi {
@Anonymous @Anonymous
@ApiOperation(value = "短信验证登陆") @ApiOperation(value = "短信验证登陆")
@PostMapping("/sms") @PostMapping("/sms")
public Response smsAuth(@RequestBody @Valid @ApiParam("短信认证表单") SmsAuthFrom smsAuthFrom, BindingResult bindingResult) throws UserServiceException { public Response smsAuth(@RequestBody @Valid @ApiParam("短信认证表单") SmsAuthFrom smsAuthFrom, BindingResult bindingResult,
@RequestParam(value = "clientType", required = false) Integer clientType) throws UserServiceException {
if (bindingResult.hasErrors()) { if (bindingResult.hasErrors()) {
return Response.fieldError(bindingResult.getFieldError()); return Response.fieldError(bindingResult.getFieldError());
} }
AuthenticationResultDTO authenticationResult = null; AuthenticationResultDTO authenticationResult = null;
ClientType type = ClientType.valueOf(clientType);
try { try {
authenticationResult = authenticationService.smsAuthentication(smsAuthFrom.getMobile(), smsAuthFrom.getVerifyCode()); authenticationResult = authenticationService.smsAuthentication(smsAuthFrom.getMobile(), smsAuthFrom.getVerifyCode(), type);
return Response.success(authenticationResult); return Response.success(authenticationResult);
} catch (AuthenticationServiceException e) { } catch (AuthenticationServiceException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -76,10 +88,30 @@ public class AuthenticationApi { ...@@ -76,10 +88,30 @@ public class AuthenticationApi {
@Anonymous @Anonymous
@ApiOperation(value = "QQ认证") @ApiOperation(value = "QQ认证")
@GetMapping("/qq") @GetMapping("/qq")
public Response<AuthenticationResultDTO> qqAuth(@RequestParam("code") String code) { public Response<AuthenticationResultDTO> qqAuth(@RequestParam("code") String code,
@RequestParam(value = "clientType", required = false) Integer clientType) {
AuthenticationResultDTO authenticationResult = null;
ClientType type = ClientType.valueOf(clientType);
try {
authenticationResult = authenticationService.qqAuthentication(code, type);
return Response.success(authenticationResult);
} catch (AuthenticationServiceException e) {
e.printStackTrace();
return Response.error(e);
}
}
@Anonymous
@ApiOperation(value = "刷新token")
@PostMapping("/refresh")
public Response refreshToken(@RequestBody @Valid RefreshTokenFrom refreshTokenFrom, BindingResult bindingResult) throws UserServiceException {
if (bindingResult.hasErrors()) {
return Response.fieldError(bindingResult.getFieldError());
}
AuthenticationResultDTO authenticationResult = null; AuthenticationResultDTO authenticationResult = null;
try { try {
authenticationResult = authenticationService.qqAuthentication(code); authenticationResult = authenticationService.refreshToken(refreshTokenFrom.getRefreshToken());
return Response.success(authenticationResult); return Response.success(authenticationResult);
} catch (AuthenticationServiceException e) { } catch (AuthenticationServiceException e) {
e.printStackTrace(); e.printStackTrace();
......
...@@ -16,4 +16,7 @@ public class AuthenticationResultDTO { ...@@ -16,4 +16,7 @@ public class AuthenticationResultDTO {
@ApiModelProperty("token") @ApiModelProperty("token")
private String accessToken; private String accessToken;
@ApiModelProperty("refreshToken")
private String refreshToken;
} }
package cn.meteor.beyondclouds.modules.user.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author meteor
*/
@NoArgsConstructor
@Data
public class TokenInfo {
public TokenInfo(String token, String userId, Integer clientType) {
this.token = token;
this.userId = userId;
this.clientType = clientType;
}
private String token;
private String userId;
private Integer clientType;
public static TokenInfo create(String token, String userId, Integer clientType) {
return new TokenInfo(token, userId, clientType);
}
}
package cn.meteor.beyondclouds.modules.user.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author meteor
*/
@NoArgsConstructor
@Data
public class TokenResult {
public TokenResult(String accessToken, String refreshToken) {
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}
private String accessToken;
private String refreshToken;
}
package cn.meteor.beyondclouds.modules.user.enums;
import io.swagger.models.auth.In;
/**
* @author meteor
*/
public enum ClientType {
WEB(1),
ANDROID(2)
;
private Integer type;
ClientType(Integer type) {
this.type = type;
}
public Integer getType() {
return type;
}
public static ClientType valueOf(Integer type) {
if (null == type) {
return WEB;
}
for (ClientType clientType : values()) {
if (clientType.getType().equals(type)) {
return clientType;
}
}
return WEB;
}
}
package cn.meteor.beyondclouds.modules.user.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author meteor
*/
@ApiModel("刷新token表单")
@Data
public class RefreshTokenFrom {
@ApiModelProperty("refresh_token")
private String refreshToken;
}
...@@ -2,6 +2,7 @@ package cn.meteor.beyondclouds.modules.user.service; ...@@ -2,6 +2,7 @@ package cn.meteor.beyondclouds.modules.user.service;
import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO; import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO;
import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO; import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO;
import cn.meteor.beyondclouds.modules.user.enums.ClientType;
import cn.meteor.beyondclouds.modules.user.exception.AuthenticationServiceException; import cn.meteor.beyondclouds.modules.user.exception.AuthenticationServiceException;
import cn.meteor.beyondclouds.modules.user.exception.UserServiceException; import cn.meteor.beyondclouds.modules.user.exception.UserServiceException;
...@@ -17,24 +18,27 @@ public interface IAuthenticationService { ...@@ -17,24 +18,27 @@ public interface IAuthenticationService {
* 根据手机号和密码认证用户 * 根据手机号和密码认证用户
* @param account * @param account
* @param password * @param password
* @param clientType
* @return * @return
*/ */
AuthenticationResultDTO localAuthentication(String account, String password) throws AuthenticationServiceException; AuthenticationResultDTO localAuthentication(String account, String password, ClientType clientType) throws AuthenticationServiceException;
/** /**
* QQ认证 * QQ认证
* @param code * @param code
* @param clientType
* @return * @return
*/ */
AuthenticationResultDTO qqAuthentication(String code) throws AuthenticationServiceException; AuthenticationResultDTO qqAuthentication(String code, ClientType clientType) throws AuthenticationServiceException;
/** /**
* 短信验证登陆 * 短信验证登陆
* @param mobile * @param mobile
* @param verifyCode * @param verifyCode
* @param clientType
* @return * @return
*/ */
AuthenticationResultDTO smsAuthentication(String mobile, String verifyCode) throws UserServiceException, AuthenticationServiceException; AuthenticationResultDTO smsAuthentication(String mobile, String verifyCode, ClientType clientType) throws UserServiceException, AuthenticationServiceException;
/** /**
* 获取我的认证列表 * 获取我的认证列表
...@@ -42,4 +46,11 @@ public interface IAuthenticationService { ...@@ -42,4 +46,11 @@ public interface IAuthenticationService {
* @return * @return
*/ */
List<UserAuthDTO> getAuths(String userId); List<UserAuthDTO> getAuths(String userId);
/**
* 刷新token
* @param refreshToken
* @return
*/
AuthenticationResultDTO refreshToken(String refreshToken) throws AuthenticationServiceException;
} }
...@@ -5,11 +5,15 @@ import cn.meteor.beyondclouds.common.exception.QQAuthenticationException; ...@@ -5,11 +5,15 @@ import cn.meteor.beyondclouds.common.exception.QQAuthenticationException;
import cn.meteor.beyondclouds.common.helper.IQQAuthenticationHelper; import cn.meteor.beyondclouds.common.helper.IQQAuthenticationHelper;
import cn.meteor.beyondclouds.common.helper.IRedisHelper; import cn.meteor.beyondclouds.common.helper.IRedisHelper;
import cn.meteor.beyondclouds.core.authentication.Subject; import cn.meteor.beyondclouds.core.authentication.Subject;
import cn.meteor.beyondclouds.core.emuns.AuthorizationErrorCode;
import cn.meteor.beyondclouds.core.exception.AuthorizationException;
import cn.meteor.beyondclouds.core.queue.message.UserActionMessage; import cn.meteor.beyondclouds.core.queue.message.UserActionMessage;
import cn.meteor.beyondclouds.core.redis.RedisKey; import cn.meteor.beyondclouds.core.redis.RedisKey;
import cn.meteor.beyondclouds.core.redis.TokenManager; import cn.meteor.beyondclouds.core.redis.TokenManager;
import cn.meteor.beyondclouds.modules.queue.service.IMessageQueueService; import cn.meteor.beyondclouds.modules.queue.service.IMessageQueueService;
import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO; import cn.meteor.beyondclouds.modules.user.dto.AuthenticationResultDTO;
import cn.meteor.beyondclouds.modules.user.dto.TokenInfo;
import cn.meteor.beyondclouds.modules.user.dto.TokenResult;
import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO; import cn.meteor.beyondclouds.modules.user.dto.UserAuthDTO;
import cn.meteor.beyondclouds.modules.user.entity.User; import cn.meteor.beyondclouds.modules.user.entity.User;
import cn.meteor.beyondclouds.modules.user.entity.UserAuthApp; import cn.meteor.beyondclouds.modules.user.entity.UserAuthApp;
...@@ -75,7 +79,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -75,7 +79,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
} }
@Override @Override
public AuthenticationResultDTO localAuthentication(String account, String password) throws AuthenticationServiceException { public AuthenticationResultDTO localAuthentication(String account, String password, ClientType clientType) throws AuthenticationServiceException {
//1. 查找用户是否存在 //1. 查找用户是否存在
UserAuthLocal userAuthLocal = userAuthLocalService.getByAccount(account); UserAuthLocal userAuthLocal = userAuthLocalService.getByAccount(account);
if (null == userAuthLocal) { if (null == userAuthLocal) {
...@@ -109,14 +113,14 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -109,14 +113,14 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
} }
// 根据userId生成token并返回 // 根据userId生成token并返回
AuthenticationResultDTO authenticationResultDTO = makeAuthenticationResult(userAuthLocal.getUserId()); AuthenticationResultDTO authenticationResultDTO = makeAuthenticationResult(userAuthLocal.getUserId(), clientType);
sendUserLoginMessage(userAuthLocal); sendUserLoginMessage(userAuthLocal, clientType);
return authenticationResultDTO; return authenticationResultDTO;
} }
@Override @Override
public AuthenticationResultDTO qqAuthentication(String code) throws AuthenticationServiceException { public AuthenticationResultDTO qqAuthentication(String code, ClientType clientType) throws AuthenticationServiceException {
QQAuthResultDTO qqAuthResult; QQAuthResultDTO qqAuthResult;
try { try {
// 1.进行QQ认证,获取认证结果 // 1.进行QQ认证,获取认证结果
...@@ -136,7 +140,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -136,7 +140,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
} }
// 根据userId生成token并返回 // 根据userId生成token并返回
return makeAuthenticationResult(userId); return makeAuthenticationResult(userId, clientType);
} catch (QQAuthenticationException e) { } catch (QQAuthenticationException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -145,7 +149,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -145,7 +149,7 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
} }
@Override @Override
public AuthenticationResultDTO smsAuthentication(String mobile, String verifyCode) throws UserServiceException, AuthenticationServiceException { public AuthenticationResultDTO smsAuthentication(String mobile, String verifyCode, ClientType clientType) throws UserServiceException, AuthenticationServiceException {
//1.检查验证码是否正确 //1.检查验证码是否正确
String realVerifyCode = redisHelper.get(RedisKey.MOBILE_VERIFY_CODE(mobile)); String realVerifyCode = redisHelper.get(RedisKey.MOBILE_VERIFY_CODE(mobile));
...@@ -166,8 +170,8 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -166,8 +170,8 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
// 根据userId生成token并返回 // 根据userId生成token并返回
AuthenticationResultDTO authenticationResultDTO = makeAuthenticationResult(userAuthLocal.getUserId()); AuthenticationResultDTO authenticationResultDTO = makeAuthenticationResult(userAuthLocal.getUserId(), clientType);
sendUserLoginMessage(userAuthLocal); sendUserLoginMessage(userAuthLocal, clientType);
return authenticationResultDTO; return authenticationResultDTO;
} }
...@@ -175,22 +179,26 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -175,22 +179,26 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
/** /**
* 制造认证结果 * 制造认证结果
* @param userId * @param userId
* @param clientType
* @return * @return
*/ */
private AuthenticationResultDTO makeAuthenticationResult(String userId) { private AuthenticationResultDTO makeAuthenticationResult(String userId, ClientType clientType) {
AuthenticationResultDTO result = new AuthenticationResultDTO(); AuthenticationResultDTO result = new AuthenticationResultDTO();
TokenResult tokenResult = tokenManager.generateToken(userId, clientType);
result.setUserId(userId); result.setUserId(userId);
result.setAccessToken(tokenManager.generateToken(userId, 60 * 120)); result.setAccessToken(tokenResult.getAccessToken());
result.setRefreshToken(tokenResult.getRefreshToken());
return result; return result;
} }
/** /**
* 发送用户登录消息 * 发送用户登录消息
* @param userAuthLocal * @param userAuthLocal
* @param clientType
*/ */
private void sendUserLoginMessage(UserAuthLocal userAuthLocal) { private void sendUserLoginMessage(UserAuthLocal userAuthLocal, ClientType clientType) {
Subject subject = SubjectUtils.getSubject(); Subject subject = SubjectUtils.getSubject();
messageQueueService.sendUserActionMessage(UserActionMessage.loginMessage(Subject.authenticated(userAuthLocal.getUserId(), subject.getIpAddress()), userAuthLocal)); messageQueueService.sendUserActionMessage(UserActionMessage.loginMessage(Subject.authenticated(userAuthLocal.getUserId(), clientType.getType(), subject.getIpAddress()), userAuthLocal));
} }
...@@ -233,4 +241,13 @@ public class AuthenticationServiceImpl implements IAuthenticationService { ...@@ -233,4 +241,13 @@ public class AuthenticationServiceImpl implements IAuthenticationService {
return auths; return auths;
} }
@Override
public AuthenticationResultDTO refreshToken(String refreshToken) throws AuthenticationServiceException {
TokenInfo tokenInfo = tokenManager.getRefreshTokenInfo(refreshToken);
if (null == tokenInfo) {
throw new AuthenticationServiceException(AuthorizationErrorCode.REFRESH_TOKEN_VERIFY_FAILURE);
}
return makeAuthenticationResult(tokenInfo.getUserId(), ClientType.valueOf(tokenInfo.getClientType()));
}
} }
...@@ -5,6 +5,7 @@ import cn.meteor.beyondclouds.common.dto.QQAuthResultDTO; ...@@ -5,6 +5,7 @@ import cn.meteor.beyondclouds.common.dto.QQAuthResultDTO;
import cn.meteor.beyondclouds.common.exception.OssException; import cn.meteor.beyondclouds.common.exception.OssException;
import cn.meteor.beyondclouds.common.helper.IOssHelper; import cn.meteor.beyondclouds.common.helper.IOssHelper;
import cn.meteor.beyondclouds.common.helper.IRedisHelper; import cn.meteor.beyondclouds.common.helper.IRedisHelper;
import cn.meteor.beyondclouds.core.authentication.Subject;
import cn.meteor.beyondclouds.core.queue.message.DataItemChangeMessage; import cn.meteor.beyondclouds.core.queue.message.DataItemChangeMessage;
import cn.meteor.beyondclouds.core.queue.message.DataItemType; import cn.meteor.beyondclouds.core.queue.message.DataItemType;
import cn.meteor.beyondclouds.core.queue.message.UserActionMessage; import cn.meteor.beyondclouds.core.queue.message.UserActionMessage;
...@@ -630,8 +631,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU ...@@ -630,8 +631,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
@Override @Override
public void logout() { public void logout() {
if (SubjectUtils.isAuthenticated()) { if (SubjectUtils.isAuthenticated()) {
String userId = (String) SubjectUtils.getSubject().getId(); Subject subject = SubjectUtils.getSubject();
tokenManager.removeToken(userId); tokenManager.removeTokenAndRefreshToken(String.valueOf(subject.getId()), subject.getClientType());
messageQueueService.sendUserActionMessage(UserActionMessage.logoutMessage(SubjectUtils.getSubject())); messageQueueService.sendUserActionMessage(UserActionMessage.logoutMessage(SubjectUtils.getSubject()));
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment