在SpringBoot中使用JWT的实现方法

下面我将为您讲解在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技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • PHP性能优化大全(php.ini)

    关于 PHP 性能优化,我们需要从 PHP 配置文件 php.ini 开始说起。php.ini 是 PHP 的配置文件,它包含了一系列的指令,可以用来配置 PHP 的环境和运行时行为。在优化 PHP 性能的过程中,我们可以对 php.ini 文件进行一些调整来达到优化的效果。 以下是完整的 PHP 性能优化攻略: 1. 开启 OPCACHE OPCACHE …

    Java 2023年5月20日
    00
  • 深入理解Java的Spring框架中的IOC容器

    深入理解Java的Spring框架中的IOC容器 什么是IOC IOC全称 Inversion of Control,即控制反转。它是一种设计模式,用于减少计算机程序的耦合,使程序更加灵活,易于维护和扩展。在计算机程序中,对象之间的关系很密切,一个对象依赖于另一个对象,如果硬编码这些关系,就会造成程序的耦合度很高,不容易维护和扩展。而控制反转就是将这些对象之…

    Java 2023年5月19日
    00
  • java实现FTP文件上传与文件下载

    下面是Java实现FTP文件上传与文件下载的完整攻略: 一、准备工作 在进行Java实现FTP文件上传与下载之前,需要进行一些准备工作。如下所示: 需要使用FTP服务器,可以使用FileZilla等软件搭建,也可以直接使用云服务器上的FTP服务。 需要引入FTP客户端库,可以使用Apache Commons Net等开源库。 获取FTP服务器的IP地址、端口…

    Java 2023年5月19日
    00
  • Java中的继承是什么?

    Java中的继承是面向对象编程中很重要的一种机制。通过继承,我们可以创建一个新类,从已有的类中继承属性和方法,并且可以对这些属性和方法进行修改、扩展或重写。继承可以提高代码的复用性,减少代码冗余,简化程序设计。 Java中,继承是通过使用 extends 关键字来实现的。下面是一个简单的示例: public class Animal { public voi…

    Java 2023年4月27日
    00
  • JavaSpringBoot报错“WebApplicationException”的原因和处理方法

    当使用Java的Spring Boot框架时,可能会遇到“WebApplicationException”错误。这个错误通常是由以下原因之一引起的: 请求处理错误:如果请求处理过程中出现错误,则可能会出现此错误。在这种情况下,需要检查请求处理代码并进行必要的更改。 响应处理错误:如果响应处理过程中出现错误,则可能会出现此错误。在这种情况下,需要检查响应处理代…

    Java 2023年5月5日
    00
  • 浅谈java web中常用对象对应的实例化接口

    我们来详细讲解一下“浅谈Java Web中常用对象对应的实例化接口”的完整攻略。 一、Java Web中常用对象的实例化接口 在Java Web开发中,常用的对象包括Servlet、JSP、HttpServletRequest、HttpServletResponse等。这些对象的实例化需要通过相应的接口来完成。 具体来说,常用对象的实例化接口如下: Serv…

    Java 2023年6月15日
    00
  • Jsp页面实现文件上传下载类代码第2/2页

    我会尽可能详细地讲解”Jsp页面实现文件上传下载类代码”的完整攻略。 首先,我们来讲一下文件上传的实现过程。 文件上传 HTML表单 要上传文件,我们首先需要在HTML表单中添加一个<input type=”file”>元素,例如: <form action="fileUpload.jsp" method="p…

    Java 2023年6月15日
    00
  • Spring session 获取当前账户登录数的实例代码

    Spring Session 是 Spring 提供的用于在分布式系统中管理用户会话信息的解决方案。通过使用 Spring Session,我们可以将用户的会话信息存储在外部存储中,实现会话状态在多个应用之间的共享,从而解决多个应用之间无法共享会话状态的问题。 在 Spring Session 中,我们可以使用 SessionRegistry 接口来获取当前…

    Java 2023年6月16日
    00
合作推广
合作推广
分享本页
返回顶部