下面我将为您讲解在SpringBoot中使用JWT的实现方法的完整攻略。
1. 什么是JWT
JWT全称是Json Web Token,它是一种基于 JSON 的开放标准(RFC 7519) ,用于在不同的系统之间传递信息,并且保证信息不会被篡改。在进行用户认证、鉴权等领域,JWT被广泛应用。
JWT由三部分组成:
- Header 头部
- Payload 载荷(有效的信息)
- Signature 签名
通过Base64加密,三个部分将被组合在一起,成为一个JWT字符串。
2. 在SpringBoot中使用JWT的步骤
2.1 添加依赖
Spring Security JWT需要依赖JJWT,在pom.xml中添加依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.2 配置JWT工具类
在项目中,需要封装一个JWT工具类,来处理JWT的生成、解析等操作,代码示例:
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
/**
* 生成jwt字符串
* @param userId
* @param username
* @return
*/
public String generateToken(Integer userId, String username) {
Date nowDate = new Date();
//过期时间
Date expireDate = new Date(nowDate.getTime() + 1000 * 60 * 60 * 24 * 7);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(userId.toString())
.setIssuedAt(nowDate)
.setExpiration(expireDate)
.claim("username", username)
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
/**
* 获取jwt中的用户信息
* @param token
* @return
*/
public Claims getClaimByToken(String token) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
return null;
}
}
/**
* 判断jwt是否过期失效
* @param expiration
* @return true:过期失效
*/
public boolean isTokenExpired(Date expiration) {
return expiration.before(new Date());
}
}
在生成和解析Token时,需要用到指定的加密密钥,这里使用@Value("${jwt.secret}")
注入配置文件中配置的密钥。
2.3 自定义UserDetails实现
Spring Security在用户认证中需要知道哪些用户是合法的,哪些用户具有哪些角色和权限。在Spring中使用UserDetailsService接口,通过在该接口的实现类中返回一个 UserDetails 对象来完成用户认证。在这里我们自定义了MyUserDetails类,来实现这个接口,并重写其方法。示例代码:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserService userService;
public UserDetailsServiceImpl(UserService userService) {
this.userService = userService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getUserByUsername(username);
if (Objects.isNull(user)) {
throw new UsernameNotFoundException("用户不存在");
}
return new MyUserDetails(user);
}
}
2.4 自定义SecurityConfig配置类
最后一步,我们需要设置WebSecurityConfigurerAdapter,该类是Spring Security提供给开发人员的另一个配置接口。该配置类提供一系列方法来配置Spring Security的安全行为。该类需要自定义编写,并配置相关登录、登出等内容。我们需要继承该类并进行配置。配置过程中,为了保护特定的路径(例如接口),我们将采用 TokenAuthenticationFilter
配置的方式。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final UserDetailsServiceImpl userDetailsService;
private final JwtTokenFilter jwtTokenFilter;
public SecurityConfig(JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, UserDetailsServiceImpl userDetailsService, JwtTokenFilter jwtTokenFilter) {
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
this.jwtTokenFilter = jwtTokenFilter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
// 对于登录、注册允许匿名访问
.antMatchers("/auth/**").permitAll()
.antMatchers(HttpMethod.GET, "/user/**").hasAuthority(Role.USER.getRoleName())
.antMatchers(HttpMethod.POST, "/book/**").hasAuthority(Role.ADMIN.getRoleName())
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()
.cors()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//添加JWT filter
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加自定义未授权和未登录结果返回
http.exceptionHandling()
.accessDeniedHandler(jwtAuthenticationEntryPoint)
.authenticationEntryPoint(jwtAuthenticationEntryPoint);
}
@Override
public void configure(WebSecurity web) throws Exception {
//ignoring Swagger UI resource
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**",
"/configuration/security", "/swagger-ui.html", "/webjars/**", "/favicon.ico", "/index.html");
}
}
上面的代码显示,利用 HttpSecurity
配置器,我们禁用了 CSRF
,但允许匿名访问 /auth
,通过请求方法和授权等方式来限制接口的访问。添加了JWT filter并配置了自定义未授权和未登录的结果返回。
至此,我们完成了JWT的基本配置,并且可以实现用户的认证和用户鉴权。
3. JWT的使用示例
3.1 生成Token
以下代码片段为我们展示如何生成JWT,生成过程需要用到上面讲到的JwtUtil工具类。
@RequestMapping(value = "/login", method = RequestMethod.POST)
public CommonResult login(@RequestParam(name = "username") String username,
@RequestParam(name = "password") String password){
User user = userService.getUserByUsername(username);
if(Objects.isNull(user)){
return CommonResult.failed("用户不存在");
}
if(!passwordEncoder.matches(password,user.getPassword())){
return CommonResult.failed("密码不正确");
}
//登录成功,生成token
String token = jwtUtil.generateToken(user.getId(), user.getUsername());
Map<String,String> result = new HashMap<>();
result.put("token",token);
result.put("tokenHead",tokenProperties.getTokenHead());
return CommonResult.success(result);
}
3.2 接口鉴权
通过上面的配置,我们可以为指定的接口添加鉴权,示例代码如下:
@RestController
@RequestMapping("/book")
@RequiredArgsConstructor
@Api(tags = "图书管理接口")
public class BookController {
private final BookService bookService;
@GetMapping("/{id}")
@ApiOperation("获取图书详情")
@ApiImplicitParam(name = "id", value = "图书ID", required = true, dataType = "int", paramType = "path")
@PreAuthorize("hasAuthority('USER')")
public CommonResult<Book> getBookById(@PathVariable int id){
return bookService.getBookById(id);
}
@PostMapping
@ApiOperation("新增图书")
@ApiImplicitParam(name = "book", value = "图书信息", required = true, dataType = "Book")
@PreAuthorize("hasAuthority('ADMIN')")
public CommonResult addBook(@RequestBody @Valid Book book){
return bookService.addBook(book);
}
}
其中,@PreAuthorize("hasAuthority('USER')")
表示只有拥有USER角色的用户才可以调用该接口。
总结
以上就是在SpringBoot中使用JWT的实现方法的完整攻略,希望对您有所帮助。JWT作为一种常见的用户认证、鉴权,确保我们的服务不易被攻击,可以为我们的项目安全加上一道保护墙,同时也提高了开发效率、降低了维护成本。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:在SpringBoot中使用JWT的实现方法 - Python技术站