前端 (Vue.js)
1. 创建Vue项目
首先,创建一个新的Vue项目。如果你还没有安装Vue CLI,可以通过以下命令进行安装:
npm install -g @vue/cli
然后创建一个新的Vue项目:
1. vue create jwt-auth-demo 2. cd jwt-auth-demo
2. 安装Axios
我们将使用Axios来处理HTTP请求。安装Axios:
npm install axios
3. 创建登录组件
在src
目录下,创建一个Login.vue
组件:
<template> <div> <h2>Login</h2> <form @submit.prevent="login"> <div> <label for="username">Username:</label> <input type="text" v-model="username" required /> </div> <div> <label for="password">Password:</label> <input type="password" v-model="password" required /> </div> <button type="submit">Login</button> </form> <p v-if="error">{{ error }}</p> </div> </template> <script> import axios from 'axios'; export default { data() { return { username: '', password: '', error: '' }; }, methods: { async login() { try { const response = await axios.post('http://localhost:8080/api/auth/login', { username: this.username, password: this.password }); localStorage.setItem('token', response.data.token); this.$router.push('/'); } catch (err) { this.error = 'Invalid username or password'; } } } }; </script>
4. 配置路由
在src/router/index.js
中,配置路由以包含登录页面和受保护的主页
import Vue from 'vue'; import Router from 'vue-router'; import Login from '@/components/Login.vue'; import Home from '@/components/Home.vue'; Vue.use(Router); const router = new Router({ routes: [ { path: '/', name: 'Home', component: Home, meta: { requiresAuth: true } }, { path: '/login', name: 'Login', component: Login } ] }); router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some(record => record.meta.requiresAuth); const token = localStorage.getItem('token'); if (requiresAuth && !token) { next('/login'); } else { next(); } }); export default router;
5. 创建主页组件
在src/components
目录下,创建一个Home.vue
组件:
<template> <div> <h2>Home</h2> <p>Welcome to the protected home page!</p> </div> </template> <script> export default { created() { const token = localStorage.getItem('token'); if (!token) { this.$router.push('/login'); } } }; </script>
6. 设置Axios拦截器
在src/main.js
中,设置Axios拦截器以在每个请求中添加JWT:
import Vue from 'vue'; import App from './App.vue'; import router from './router'; import axios from 'axios'; Vue.config.productionTip = false; axios.interceptors.request.use( config => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => { return Promise.reject(error); } ); new Vue({ router, render: h => h(App) }).$mount('#app');
后端 (Spring Boot)
1. 创建Spring Boot项目
使用Spring Initializr创建一个新的Spring Boot项目,并添加以下依赖:
- Spring Web
- Spring Security
- Spring Data JPA
- MySQL Driver
- Lombok
- jjwt (JSON Web Token)
2. 配置数据库连接
在application.properties
中配置数据库连接信息:
spring.datasource.url=jdbc:mysql://localhost:3306/jwt_auth_demo spring.datasource.username=root spring.datasource.password=yourpassword spring.jpa.hibernate.ddl-auto=update
3. 创建用户实体
创建一个User
实体类:
package com.example.jwt.model; import lombok.Data; import javax.persistence.*; @Data @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; }
4. 创建用户仓库
创建一个UserRepository
接口:
package com.example.jwt.repository; import com.example.jwt.model.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); }
5. 创建JWT工具类
创建一个JwtUtil
工具类来生成和验证JWT:
package com.example.jwt.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Component; import java.util.Date; @Component public class JwtUtil { private static final String SECRET_KEY = "secret"; public String generateToken(String username) { return Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public Claims extractClaims(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); } public String extractUsername(String token) { return extractClaims(token).getSubject(); } public boolean isTokenExpired(String token) { return extractClaims(token).getExpiration().before(new Date()); } public boolean validateToken(String token, String username) { return (extractUsername(token).equals(username) && !isTokenExpired(token)); } }
6. 创建用户服务
创建一个UserService
来处理用户相关的逻辑:
package com.example.jwt.service; import com.example.jwt.model.User; import com.example.jwt.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; public User save(User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); return userRepository.save(user); } public User findByUsername(String username) { return userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); } }
7. 创建Spring Security配置
创建一个SecurityConfig
类来配置Spring Security:
package com.example.jwt.config; import com.example.jwt.service.UserService; import com.example.jwt.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private JwtUtil jwtUtil; @Bean public JwtRequestFilter jwtRequestFilter() { return new JwtRequestFilter(jwtUtil, userService); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService::findByUsername) .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/api/auth/login").permitAll() .anyRequest().authenticated() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }