Skip to content

Commit

Permalink
Merge pull request #96 from NJUPT-SAST/dev-felmose
Browse files Browse the repository at this point in the history
Dev felmose
  • Loading branch information
feellmoose authored Dec 9, 2023
2 parents 9025a17 + 04876c1 commit 6d20739
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 49 deletions.
8 changes: 3 additions & 5 deletions src/main/java/sast/evento/controller/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,13 @@ public Map<String,Object> bindStudentId(@RequestParam String studentId,

/**
* 获取授权给新设备登录的ticket
* @param studentId 学号
* @return Map
*/
@OperateLog("获取ticket")
@PostMapping("/login/ticket/get")
@DefaultActionState(ActionState.PUBLIC)
public Map<String, Object> getTicket(@RequestParam String studentId,
@RequestParam(required = false) String ticket){
return loginService.getLoginTicket(studentId,ticket);
public Map<String, Object> getTicket(@RequestParam(required = false) String ticket){
return loginService.getLoginTicket(ticket);
}

/**
Expand All @@ -99,7 +97,7 @@ public Map<String, Object> getTicket(@RequestParam String studentId,
@DefaultActionState(ActionState.LOGIN)
public String loginByTicket(@RequestParam String ticket){
UserModel user = HttpInterceptor.userHolder.get();
loginService.checkTicket(user.getStudentId(), ticket);
loginService.checkLoginTicket(ticket,user.getId());
return "ok";
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/sast/evento/service/LoginService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sast.evento.service;

import jakarta.annotation.Nullable;
import sast.sastlink.sdk.exception.SastLinkException;

import java.util.Map;
Expand All @@ -15,9 +16,9 @@ public interface LoginService {

Map<String, Object> bindStudentOnWechat(String userId, String studentId, Boolean force);

Map<String, Object> getLoginTicket(String studentId, String ticket);
Map<String, Object> getLoginTicket(String ticket);

void checkTicket(String studentId, String ticket);
void checkLoginTicket(String ticket,String userId);

void bindPassword(String studentId, String password);

Expand Down
83 changes: 53 additions & 30 deletions src/main/java/sast/evento/service/impl/LoginServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sast.evento.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -52,7 +54,7 @@ public class LoginServiceImpl implements LoginService {
private RedisUtil redisUtil;
private static final String LOGIN_TICKET = "ticket:";
private static final String LOGIN_SUCCESS = "login:";
private static final long LOGIN_TICKET_EXPIRE = 600;
private static final long LOGIN_TICKET_EXPIRE = 60;

/**
* 这边逻辑和业务强耦合,建议先熟悉登陆流程再阅读代码
Expand Down Expand Up @@ -118,43 +120,40 @@ public Map<String, Object> wxLogin(String code) {
return Map.of("unionid", jsCodeSessionResponse.getUnionid(), "userInfo", user, "token", token);
}

//未登录展示保持连接并等待(检查Ticket更改状态)
@Override
public Map<String, Object> getLoginTicket(String studentId, String ticket) {
studentId = studentId.toLowerCase();
if (!userMapper.exists(Wrappers.lambdaQuery(User.class)
.eq(User::getStudentId, studentId))) {
throw new LocalRunTimeException(ErrorEnum.STUDENT_NOT_BIND);
public Map<String, Object> getLoginTicket(@Nullable String ticket) {
if (ticket == null || ticket.isEmpty()) {
String key = TicketUtil.generateKey();
return Map.of("expireIn", LOGIN_TICKET_EXPIRE, "ticket", generateTicket(key));
}
String local = (String) redisUtil.get(LOGIN_TICKET + studentId);
if (ticket != null && !ticket.isEmpty()) {
String userJson = (String) redisUtil.get(LOGIN_SUCCESS + studentId);
if (ticket.equals(local) && userJson != null) {
User user = JsonUtil.fromJson(userJson, User.class);
String token = addTokenInCache(user, false);
redisUtil.del(LOGIN_TICKET + studentId, LOGIN_SUCCESS + studentId);
return Map.of("token", token, "userInfo", user);
}
String key = TicketUtil.getInfoFromTicket(ticket)[0];
String localTicket = (String) redisUtil.get(LOGIN_TICKET + key);
if (!ticket.equals(localTicket)) {
redisUtil.del(LOGIN_TICKET + key);
key = TicketUtil.generateKey();
return Map.of("expireIn", LOGIN_TICKET_EXPIRE, "ticket", generateTicket(key));
}
if (local != null) {
return Map.of("expireIn", redisUtil.getExpire(LOGIN_TICKET + studentId), "ticket", local);
String userJson = (String) redisUtil.get(LOGIN_SUCCESS + key);
if (userJson == null || userJson.isEmpty()) {
return Map.of("expireIn", redisUtil.getExpire(LOGIN_TICKET + key), "ticket", ticket);
}
ticket = TicketUtil.generateTicket();
redisUtil.set(LOGIN_TICKET + studentId, ticket, LOGIN_TICKET_EXPIRE);
return Map.of("expireIn", LOGIN_TICKET_EXPIRE, "ticket", ticket);
User user = JsonUtil.fromJson(userJson, User.class);
String token = addTokenInCache(user, false);
redisUtil.del(LOGIN_TICKET + key, LOGIN_SUCCESS + key);
return Map.of("token", token, "userInfo", user);
}

//检查Ticket更改状态
@Override
public void checkTicket(String studentId, String ticket) {
studentId = studentId.toLowerCase();
String localTicket = (String) redisUtil.get(LOGIN_TICKET + studentId);
if (localTicket != null && localTicket.equals(ticket)) {
redisUtil.del(LOGIN_TICKET + studentId);
}
public void checkLoginTicket(String ticket, String userId) {
if (ticket == null || ticket.isEmpty())
throw new LocalRunTimeException(ErrorEnum.LOGIN_ERROR, "ticket should not be null");
String key = TicketUtil.getInfoFromTicket(ticket)[0];
String localTicket = (String) redisUtil.get(LOGIN_TICKET + key);
if (!ticket.equals(localTicket))
throw new LocalRunTimeException(ErrorEnum.LOGIN_ERROR, "error ticket please try again");
User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
.eq(User::getStudentId, studentId));
redisUtil.set(LOGIN_SUCCESS + studentId, JsonUtil.toJson(user));
.eq(User::getId, userId));
redisUtil.set(LOGIN_SUCCESS + key, JsonUtil.toJson(user));
}


Expand Down Expand Up @@ -278,5 +277,29 @@ private String generateToken(UserModel user) {
return jwtUtil.generateToken(payload);
}

private String getTicket(@Nonnull String ticket) {
String key = TicketUtil.generateKey();
return (!checkTicket(ticket)) ? generateTicket(key) : ticket;
}

private String generateTicket(String key) {
int times = 0;
String ticket = TicketUtil.generateTicket(key);
while (!redisUtil.setnx(LOGIN_TICKET + key, ticket, LOGIN_TICKET_EXPIRE, TimeUnit.SECONDS) && times < 5) {
key = TicketUtil.generateKey();
ticket = TicketUtil.generateTicket(key);
times++;
}
if (times == 5) throw new LocalRunTimeException(ErrorEnum.COMMON_ERROR, "please try again later");
return ticket;
}

private boolean checkTicket(String ticket) {
String[] info = TicketUtil.getInfoFromTicket(ticket);
String key = info[0];
String localTicket = (String) redisUtil.get(LOGIN_TICKET + key);
return localTicket != null && localTicket.equals(ticket);
}


}
47 changes: 35 additions & 12 deletions src/main/java/sast/evento/utils/TicketUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,42 @@

public class TicketUtil {

public static String generateTicket(){
char[] chars = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
"1234567890!@#$%^&*()_+").toCharArray();
StringBuilder sb = new StringBuilder();
int size = 50;
for(int i = 0; i < size; i++){
//Random().nextInt()返回值为[0,n)
char aChar = chars[ThreadLocalRandom.current().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}

public static String generateTicket(String key, String randomStr) {
return key + "::" + System.currentTimeMillis() + "::" + randomStr;
}

public static String generateTicket() {
return generateKey() + "::" + System.currentTimeMillis() + "::" + generateRandomStr();
}

public static String generateTicket(String key) {
return key + "::" + System.currentTimeMillis() + "::" + generateRandomStr();
}


public static String[] getInfoFromTicket(String ticket){
int p1 = ticket.indexOf(':');
int p2 = ticket.lastIndexOf(':');
return new String[]{ticket.substring(0,p1),ticket.substring(p1+2,p2-1),ticket.substring(p1+1)};
}

public static String generateRandomStr() {
char[] chars = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
"1234567890!@#$%^&*()_+").toCharArray();
StringBuilder sb = new StringBuilder();
int size = 50;
for (int i = 0; i < size; i++) {
//Random().nextInt()返回值为[0,n)
char aChar = chars[ThreadLocalRandom.current().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}

public static String generateKey() {
return String.valueOf(Math.abs(ThreadLocalRandom.current().nextLong()));
}


}

0 comments on commit 6d20739

Please sign in to comment.