统一身份认证系统
小明:嘿,李工,最近我在开发一个需要用户登录后才能查看排行榜的应用,我应该怎么做呢?
李工:你好,小明。这个问题涉及到两个关键点:一个是统一身份认证系统,另一个是排行榜功能。你先告诉我,你们目前有没有使用什么认证框架?比如Spring Security、JWT或者OAuth2?
小明:我们用的是Spring Boot和JWT来处理用户认证,不过现在想把排行榜功能加进去,但不知道怎么和认证系统结合。
李工:好的,那我们可以从两个方面入手:首先确保用户登录后才能访问排行榜,其次要根据用户的权限或积分来显示不同的排名信息。
小明:明白了。那具体的实现步骤是怎样的呢?能给我一个例子吗?
李工:当然可以。我们可以先写一个简单的用户登录接口,然后在排行榜接口中加入权限校验逻辑。同时,我们还可以在数据库中存储用户的积分或得分,用于生成排行榜。
小明:听起来不错。那具体代码怎么写呢?能不能展示一下?
李工:好,我来给你写一段Spring Boot的示例代码。首先是一个登录接口,返回JWT令牌:
@RestController
public class AuthController {
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request) {
// 假设这里验证用户名和密码
if ("admin".equals(request.getUsername()) && "123456".equals(request.getPassword())) {
String token = JwtUtil.generateToken("admin");
return ResponseEntity.ok(token);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
}
}
}
小明:这个看起来很基础,那接下来是怎么在排行榜接口中使用这个token呢?
李工:我们需要在请求头中带上Authorization: Bearer {token},然后在控制器中解析这个token,获取用户信息,再进行权限判断。
小明:那具体怎么实现呢?
李工:我们可以使用Spring Security的过滤器来拦截请求,或者直接在每个接口中手动解析token。这里我给你一个简单的例子:
@RestController
public class LeaderboardController {
@GetMapping("/leaderboard")
public ResponseEntity<List<UserScore>> getLeaderboard(@RequestHeader("Authorization") String token) {
String username = JwtUtil.extractUsername(token);
if (username == null || !isValidUser(username)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
List<UserScore> scores = userService.getTopScores();
return ResponseEntity.ok(scores);
}
private boolean isValidUser(String username) {
// 这里可以检查用户是否有效,是否有权限访问排行榜
return true;
}
}
小明:这个代码看起来没问题,那用户数据和积分是怎么存储的呢?
李工:通常我们会有一个User表和一个Score表。User表存储用户的基本信息,比如id、username、password等;Score表存储用户的积分或得分,关联到User表。
小明:那数据库应该怎么设计呢?
李工:这是一个典型的多对一关系。例如,用户表(users)和积分表(scores):
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL
);
CREATE TABLE scores (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
score INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
小明:这样设计确实合理。那排行榜接口怎么获取数据呢?
李工:你可以使用JPA或者MyBatis来查询数据。下面是一个简单的JPA示例:

@Repository
public interface ScoreRepository extends JpaRepository<Score, Long> {
@Query("SELECT s FROM Score s ORDER BY s.score DESC")
List<Score> findTopScores();
}
小明:明白了。那用户登录后,如何将他们的积分更新到排行榜中呢?
李工:这可以通过一个加分接口来实现。当用户完成某个操作时,调用这个接口增加他们的积分。
小明:那这个加分接口该怎么写呢?
李工:同样,我们要验证用户的身份,然后更新他们的积分。这里是一个简单的例子:
@PostMapping("/add-score")
public ResponseEntity<String> addScore(@RequestHeader("Authorization") String token, @RequestBody ScoreRequest request) {
String username = JwtUtil.extractUsername(token);
if (username == null || !isValidUser(username)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Unauthorized");
}
User user = userRepository.findByUsername(username);
Score score = new Score();
score.setUserId(user.getId());
score.setScore(request.getScore());
scoreRepository.save(score);
return ResponseEntity.ok("Score added successfully");
}
小明:这个代码看起来没问题。那如果用户没有登录,他们还能看到排行榜吗?
李工:不能。因为我们已经在排行榜接口中加入了身份验证逻辑,如果没有token或者token无效,就会返回403错误。
小明:明白了。那整个流程就是:用户登录 -> 获取token -> 访问排行榜 -> 如果有权限,就显示数据。
李工:没错。这就是统一身份认证系统和排行榜功能的结合方式。
小明:那如果我要扩展排行榜功能,比如按时间排序、按类型筛选,该怎么办呢?
李工:你可以通过添加参数来实现。例如,在排行榜接口中添加sortType和filterType参数,然后根据这些参数动态查询数据。
小明:那具体的代码怎么修改呢?
李工:我们可以使用Spring Data JPA的动态查询功能,或者直接拼接SQL语句。这里是一个简单的例子:
@GetMapping("/leaderboard")
public ResponseEntity<List<UserScore>> getLeaderboard(
@RequestHeader("Authorization") String token,
@RequestParam(required = false) String sortType,
@RequestParam(required = false) String filterType) {
String username = JwtUtil.extractUsername(token);
if (username == null || !isValidUser(username)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
List<UserScore> scores = userService.getTopScores(sortType, filterType);
return ResponseEntity.ok(scores);
}
小明:这个方法很灵活,可以根据需求扩展。那还有没有其他需要注意的地方呢?
李工:当然有。比如,安全性方面,要防止SQL注入,使用预编译语句;性能方面,可以考虑缓存排行榜数据;另外,还要注意日志记录和异常处理。
小明:明白了。看来统一身份认证系统和排行榜功能的结合,需要从多个方面来考虑。
李工:是的。只要你在设计的时候考虑到这些点,就能做出一个安全、高效、可维护的系统。
小明:谢谢你的讲解,李工!我现在对这个项目有了更清晰的认识。
李工:不客气,随时欢迎你来问我问题。祝你项目顺利!