一、Token简单鉴权的原理
Token鉴权是一种前后端分离的权限验证方式,具体的原理如下:
-
用户登录时请求后端API,后端验证用户名和密码是否正确,如果正确,将返回一个Token给前端。
-
前端将Token保存在本地(通常是localStorage或sessionStorage),后续请求时需要将Token附带在请求头中发送给后端。
-
后端验证请求头中的Token是否存在、是否正确以及是否过期,如果鉴权通过,将返回请求所需的数据,否则返回401未授权状态码。
二、实现步骤
- 引入依赖
在pom.xml文件中引入以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
其中,spring-boot-starter-security是用于Spring Security的基本配置,jjwt是用于生成和验证Token的库。
- 配置Spring Security
在Spring Boot的配置文件application.yml中添加以下配置:
spring:
security:
user:
name: admin
password: admin
jwt:
secret: 123456
其中,security.user.name和security.user.password分别为Spring Security的默认用户名和密码,jwt.secret为Token的签名密钥。
然后在Spring Boot的启动类上添加@EnableWebSecurity注解,并继承WebSecurityConfigurerAdapter类,并重写configure(HttpSecurity http)方法:
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
// -- swagger ui
"/v2/api-docs",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**"
};
@Autowired
private TokenFilter tokenFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
该配置将所有请求都要求必须要通过认证后才能访问,同时配置了一个TokenFilter,用于鉴别请求头中的Token的有效性。
- 实现Token的生成和验证
首先在TokenUtils类中实现Token的生成和验证方法:
@Service
public class TokenUtils {
@Value("${spring.security.jwt.secret}")
private String secret;
public String generateToken(String username) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + 1440 * 60 * 1000);
return Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parse(token);
return true;
} catch (JwtException e) {
return false;
}
}
}
其中,generateToken方法用于生成Token,getUsernameFromToken方法用于获取Token中的用户名,validateToken方法用于验证Token是否有效。
然后在TokenFilter类中实现Token的验证逻辑:
public class TokenFilter extends OncePerRequestFilter {
@Autowired
private TokenUtils tokenUtils;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
final String headerToken = request.getHeader("Authorization");
String token = null;
String username = null;
if (headerToken != null && headerToken.startsWith("Bearer ")) {
// 解析token
token = headerToken.substring(7);
username = tokenUtils.getUsernameFromToken(token);
// 验证token
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null && tokenUtils.validateToken(token)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, null);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
该Filter会在所有请求到达后先从请求头中获取Token,然后经过验证后继续请求。Token的验证通过UsernamePasswordAuthenticationToken进行。将其存储到安全上下文中,保证后续的方法在需要用户信息时可以获取并调用。
三、示例
下面通过两个示例来演示如何使用Token简单鉴权:
- 登录接口示例
添加一个登录接口,用于用户登录时获取Token:
@RestController
@RequestMapping("/api")
public class LoginController {
@Autowired
private TokenUtils tokenUtils;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody Map<String, String> loginData) {
String username = loginData.get("username");
String password = loginData.get("password");
if (username.equals("admin") && password.equals("admin")) {
String token = tokenUtils.generateToken(username);
return ResponseEntity.ok(token);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
}
该接口会根据传入的用户名和密码来判断是否登录成功,如果成功,则通过TokenUtils生成一个Token并返回。否则返回401未授权状态码。
- 示例接口
在Spring Boot的Controller类中添加示例接口,用于测试Token的验证:
@RestController
@RequestMapping("/api")
public class TestController {
@GetMapping("/test")
public ResponseEntity<String> test() {
return ResponseEntity.ok("Hello World!");
}
}
该接口需要Token鉴权,如果请求头中不存在或无效的Token,将返回401未授权状态码。
那么当用户请求/api/test接口时,其请求头中应该包含有效的Token信息,否则无法通过鉴权,获取数据,该接口配置如下:
@RestController
@RequestMapping("/api")
public class TestController {
@GetMapping("/test")
public ResponseEntity<String> test() {
return ResponseEntity.ok("Hello World!");
}
}
这两个示例即可完整演示使用Token简单鉴权的实现方法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot使用token简单鉴权的具体实现方法 - Python技术站