小明:最近我们学校要开发一个教材征订管理系统,我负责的是登录模块的设计,但对技术细节不太清楚,你能不能帮我理一理思路?
小李:当然可以。首先,我们需要明确系统的整体架构,通常我们会采用前后端分离的方式,前端用Vue或React,后端用Spring Boot来处理业务逻辑。
小明:那登录模块该怎么设计呢?需要哪些技术点?
小李:登录模块的核心是验证用户身份,通常包括用户名、密码的校验,以及防止恶意攻击,比如SQL注入和XSS攻击。同时,还需要考虑会话管理,比如使用JWT(JSON Web Token)来保持用户的登录状态。
小明:听起来挺复杂的,那具体怎么实现呢?有没有具体的代码示例?
小李:我们可以从一个简单的例子开始。首先,创建一个Spring Boot项目,添加必要的依赖,比如Spring Security、Spring Data JPA和JWT库。
小明:好的,那这些依赖具体怎么写?
小李:在`pom.xml`中添加以下依赖:
小明:那接下来应该怎么编写实体类和数据库表结构?
小李:我们可以定义一个User实体类,包含id、username、password等字段,并且使用JPA进行映射。
小明:那代码怎么写?
小李:下面是一个简单的User实体类示例:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// getters and setters
}
小明:那数据库表呢?是不是要手动创建?
小李:如果使用Spring Data JPA,可以配置自动建表,或者也可以手动创建表结构。例如,使用如下SQL语句创建用户表:
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
小明:明白了。那登录接口怎么实现呢?
小李:我们可以创建一个Controller,处理登录请求。然后调用Service层进行验证,最后生成JWT令牌返回给前端。
小明:那Service层怎么写?
小李:Service层主要负责查询用户是否存在,以及密码是否匹配。这里我们可以使用Spring Security的PasswordEncoder来加密和比对密码。
小明:那具体代码是怎样的?
小李:下面是UserService的示例代码:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;

@Autowired
private PasswordEncoder passwordEncoder;
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
public boolean checkPassword(String rawPassword, String encodedPassword) {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
}
小明:那JWT是怎么生成的?
小李:我们可以使用JJWT库来生成JWT令牌。通常,我们会将用户信息(如用户名)放入Token的payload中,并设置过期时间。
小明:那生成Token的代码怎么写?
小李:下面是一个生成JWT的工具类示例:
public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION = 86400000; // 24小时
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
小明:那登录接口怎么写?
小李:我们可以创建一个LoginController,接收用户名和密码,验证成功后返回JWT令牌。
小明:那具体代码是怎样的?
小李:下面是LoginController的示例代码:
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity> login(@RequestBody LoginRequest request) {
User user = userService.findByUsername(request.getUsername());
if (user == null || !userService.checkPassword(request.getPassword(), user.getPassword())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
}

String token = JwtUtil.generateToken(user.getUsername());
return ResponseEntity.ok().header("Authorization", "Bearer " + token).build();
}
}
小明:那前端怎么获取这个Token呢?
小李:前端在登录成功后,可以从响应头中获取到Authorization字段的值,然后保存到localStorage或sessionStorage中,用于后续请求的认证。
小明:那其他接口怎么验证Token呢?
小李:我们可以使用Spring Security的Filter来拦截所有请求,检查Authorization头中的Token是否有效。

小明:那这个Filter怎么实现?
小李:我们可以自定义一个过滤器,继承OncePerRequestFilter,重写doFilterInternal方法,解析Token并设置用户信息到SecurityContext中。
小明:那具体代码是怎样的?
小李:下面是JWT过滤器的示例代码:
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
String username = JwtUtil.getUsernameFromToken(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
小明:那怎么把这个过滤器加入到Spring Security中呢?
小李:可以在SecurityConfig类中配置,添加这个过滤器到合适的路径下。
小明:那SecurityConfig怎么写?
小李:下面是SecurityConfig的示例代码:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
return http.build();
}
}
小明:这样就完成了登录模块的实现吗?
小李:是的,这就是一个完整的登录模块的基本实现。当然,在实际开发中还需要考虑更多安全机制,比如防止暴力破解、记录登录日志、增加验证码等。
小明:明白了,谢谢你的讲解!
小李:不客气,希望你能顺利实现这个功能。如果有问题,随时可以问我!
