在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日

相关文章

  • 一文理解kafka rebalance负载均衡

    一文理解Kafka Rebalance负载均衡 在Kafka中,消费者组(Consumer Group)中的多个消费者(Consumer)会协同消费一个或多个Topic的分区(Partition)。消费者组通过Partition的分配策略来确定每个消费者负责消费哪些分区。当新的消费者加入或退出消费者组时,需要重新进行分区分配,这个过程被称为Rebalance…

    Java 2023年5月20日
    00
  • 解析jdbc处理oracle的clob字段的详解

    解析jdbc处理oracle的clob字段的详解 在使用jdbc连接oracle数据库的过程中,遇到clob字段时可能会遇到一些问题。本文将介绍如何正确地使用jdbc处理oracle的clob字段。 问题描述 当使用jdbc连接oracle数据库并读取clob字段时,可能会遇到以下问题: 读取到的clob字段大小不对,可能是因为jdbc默认只读取clob字段…

    Java 2023年6月16日
    00
  • java关于String.split(“|”)的使用方式

    关于Java中String类的split()方法,当我们使用字符串来表示多个数据时,可以使用该方法按特定分隔符分隔字符串,并将拆分后的字符串返回为一个字符串数组。具体到您提到的使用方式:String.split(“|”),其中的 “|” 表示正则表达式中的“或”操作符,用于匹配多个字符中的任意一个。然而,这种写法需要注意 ‘|’ 在 Java 中是特殊字符,…

    Java 2023年5月27日
    00
  • 使用java8的方法引用替换硬编码的示例代码

    当编写Java代码时,我们经常会使用硬编码方式来实现一些操作。而Java8引入的方法引用却可以使我们的代码更加简洁而且易于维护。下面是使用Java8的方法引用替换硬编码代码的完整攻略: 1. 什么是方法引用 方法引用是一种可以用来简化Lambda表达式的写法,可以用过已有的方法来引用类的实例或类静态方法。可以将方法引用看成是Lambda表达式的精简写法。 2…

    Java 2023年5月19日
    00
  • 使用maven如何将项目中的test代码打包进jar中

    使用 Maven 将项目中的 test 代码打包进 jar 中,可以实现在发布项目时一并发布 test 代码,方便其他人也能进行测试。下面是具体的步骤: 在 pom.xml 文件中添加以下代码,指定将 test 代码打包进 jar 中: <build> <plugins> <plugin> <groupId>o…

    Java 2023年5月20日
    00
  • java中Struts2文件上传问题详解

    Java中Struts2文件上传问题详解 1. Struts2文件上传概述 在开发web应用程序中,经常需要上传文件,Java提供了很多文件上传的API,Struts2框架也提供了方便的文件上传功能。Struts2的文件上传使用commons-fileupload和commons-io库实现,包括3个部分:上传控件、Action类和文件存储位置。 2. St…

    Java 2023年5月20日
    00
  • Java实现窗体程序显示日历

    以下是详细的Java实现窗体程序显示日历的攻略: 1.准备工作 在开始编程前,需要先确定使用的开发环境和GUI工具包。一般来说,Java提供了多种GUI工具包,常见的有AWT、Swing和JavaFX等。在本文中,我们使用的是Swing工具包,因为其扩展性较强、易于学习和使用。 2.创建窗体 创建窗体需要继承JFrame类,并实现设置标题、大小、位置和关闭操…

    Java 2023年5月20日
    00
  • springsecurity基于token的认证方式

    下面我将详细讲解一下“Spring Security基于Token的认证方式”的完整攻略。 什么是Token认证方式 Token认证方式,是一种基于令牌(Token)的身份认证方式。在客户端成功登录后,服务端会生成一个Token,这个Token会放到HTTP响应头中或者响应体中返回给客户端,客户端需要在后续的请求中携带该Token才能访问资源。 Token认…

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