SpringBoot+SpringSecurity+JWT实现系统认证与授权示例

下面是“SpringBoot+SpringSecurity+JWT实现系统认证与授权”的完整攻略:

一、什么是Spring Boot、Spring Security和JWT

  • Spring Boot:是一个快速开发框架,能够简化Spring应用程序的创建和开发过程。
  • Spring Security:是Spring框架中提供的一套安全服务框架,可以用来保护Web应用程序,场景包括认证(authentication)、授权(authorization)和密码学(cryptography)等。
  • JWT(JSON Web Token):是一种基于JSON的轻量级授权和身份验证协议,主要用于Web应用程序和API的安全传输。

二、如何使用Spring Boot、Spring Security和JWT

  1. 在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.0</version>
</dependency>
  1. 配置Spring Security和JWT相关属性
    在application.yml文件中添加以下配置:
#JWT配置
jwt:
  header:
    name: Authorization
    prefix: Bearer
    secret: JWTSecretKey
    expiration: 604800000 #7天过期时间,单位毫秒
# 关闭csrf验证,jwt不需要csrf
security:
  csrf:
    enabled: false
  1. 实现Spring Security的认证和授权逻辑
    自定义一个继承了WebSecurityConfigurerAdapter类的WebSecurityConfig类,重写configure方法来实现相应的认证和授权逻辑。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    //在这里重写configure方法来实现相应的认证和授权逻辑
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/authenticate").permitAll()
                .anyRequest().authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public JwtAuthFilter authenticationJwtTokenFilter() {
        return new JwtAuthFilter();
    }
}
  1. 实现JWT的Token生成和解析逻辑
    自定义一个JwtUtils类,实现JWT的Token生成和解析逻辑。
@Component
public class JwtUtils {
    private String jwtSecret = "JWTSecretKey";
    private int jwtExpirationMs = 604800000; //7天过期时间,单位毫秒

    public String generateJwtToken(Authentication authentication) {
        UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
        return Jwts.builder()
                .setSubject((userPrincipal.getUsername()))
                .setIssuedAt(new Date())
                .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public String getUsernameFromJwtToken(String token) {
        return Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody().getSubject();
    }
}
  1. 实现JWT的认证过滤器逻辑
    自定义一个JwtAuthFilter类,实现JWT的认证过滤器逻辑。
public class JwtAuthFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        try {
            String jwt = parseJwt(request);
            if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
                String username = jwtUtils.getUsernameFromJwtToken(jwt);

                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            logger.error("Cannot set user authentication: {}", e);
        }

        filterChain.doFilter(request, response);
    }

    private String parseJwt(HttpServletRequest request) {
        String headerAuth = request.getHeader("Authorization");

        if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
            return headerAuth.substring(7, headerAuth.length());
        }

        return null;
    }
}
  1. 实现UserDetails的逻辑
    自定义一个实现UserDetails接口的UserDetailsImpl类。
public class UserDetailsImpl implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;

    public UserDetailsImpl(Integer id, String username, String password,
                            Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.authorities = authorities;
    }

    public static UserDetailsImpl build(User user) {
        List<GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getName().name()))
                .collect(Collectors.toList());

        return new UserDetailsImpl(
                user.getId(),
                user.getUsername(),
                user.getPassword(),
                authorities);
    }
    //省略getter和setter方法以及其他接口方法的实现
}
  1. 实现UserDetailsService的逻辑
    自定义一个实现UserDetailsService接口的UserDetailsServiceImpl类。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));

        return UserDetailsImpl.build(user);
    }
}

至此,我们完成了使用Spring Boot、Spring Security和JWT来实现系统认证与授权的全部步骤。

三、示例

下面是两个示例,演示如何使用Spring Boot、Spring Security和JWT来实现系统认证与授权。

示例一:用户认证

实现基于SpringBoot、SpringSecurity和JWT的用户认证演示程序,可参考以下代码:

@RestController
@RequestMapping("/api")
public class AuthController {
    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    JwtUtils jwtUtils;

    @PostMapping("/authenticate")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String jwt = jwtUtils.generateJwtToken(authentication);

        return ResponseEntity.ok(new JwtResponse(jwt));
    }
}

示例二:资源授权

实现基于SpringBoot、SpringSecurity和JWT的资源授权演示程序,可参考以下代码:

@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    UserRepository userRepository;

    @GetMapping("/users/{id}")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public ResponseEntity<User> getUserById(@PathVariable(value = "id") Integer userId) {
        User user = userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));
        return ResponseEntity.ok().body(user);
    }
}

在这个示例中,我们使用了@PreAuthorize注解,它表示只有在用户有“USER”或“ADMIN”角色时才能访问该接口。

以上是关于“SpringBoot+SpringSecurity+JWT实现系统认证与授权示例”的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot+SpringSecurity+JWT实现系统认证与授权示例 - Python技术站

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

相关文章

  • 基于spring data jpa @query返回map的踩坑记录

    我们来详细讲解一下“基于Spring Data JPA @Query返回Map的踩坑记录”的攻略。 问题描述 使用Spring Data JPA的@Query注解,执行自定义SQL查询并返回Map结果时,会出现以下问题:* 执行查询语句时,返回的结果不是Map类型;* Map类型的key不是从查询结果集中获取的。 解决方案 返回Map类型 对于第一个问题,我…

    Java 2023年6月3日
    00
  • Java 如何利用缓冲流读写文件

    Java 可以通过缓冲流来读写文件,缓冲流会将 I/O 操作的数据缓存起来,通过缓存操作可以减少访问磁盘次数,进而提升程序的性能。下面是利用缓冲流读写文件的步骤: 创建输入流对象。首先需要创建一个文件输入流对象(FileInputStream),再把它作为参数传给缓冲输入流(BufferedInputStream)的构造方法,从而创建一个缓冲输入流对象(例如…

    Java 2023年5月19日
    00
  • java字符串格式化输出实例讲解

    Java字符串格式化输出实例讲解 在Java中,我们可以使用格式化字符串来控制输出的格式。使用格式化字符串可以让我们更加方便地输出值,并且可以让输出结果更加易读。 格式化字符串的语法 格式化字符串的语法为: System.out.printf(format, argument_list); 其中format是格式化字符串,argument_list是需要输出…

    Java 2023年5月26日
    00
  • java如何交换这两个变量的值方法介绍

    下面我来为您详细讲解“java如何交换这两个变量的值方法介绍”。 在Java中,有多种方法可以交换两个变量的值,常见的方法有使用中间变量、使用加减法和使用异或运算。 使用中间变量交换变量值 这是一种最简单的方法,通过定义一个中间变量来存储变量值,然后交换两个变量的值。示例代码如下: int a = 10; int b = 20; int temp = a; …

    Java 2023年5月26日
    00
  • java导出dbf文件生僻汉字处理方式

    下面是java导出dbf文件生僻汉字处理方式的完整攻略。 总体思路 在java中,如果需要导出dbf文件中含有生僻汉字,需要进行字符集的转换,防止乱码。具体步骤如下: 将生僻汉字以GBK编码存储到List或数组中。 将List或数组中的每个字符转换成Unicode编码,并转换成16进制格式的字符串,存储到新的List或数组中。 使用Apache POI相关类…

    Java 2023年5月26日
    00
  • 如何通过LambdaProbe实现监控Tomcat

    LambdaProbe是一种轻量级的Tomcat管理和监控工具,可以帮助我们更方便地查看Tomcat运行状态、性能指标和日志等信息。下面是通过LambdaProbe实现监控Tomcat的完整攻略,包含以下内容: 下载和安装LambdaProbe 配置Tomcat 启动Tomcat和LambdaProbe 使用LambdaProbe监控Tomcat 下载和安装…

    Java 2023年6月2日
    00
  • JSP JavaBean的setProperty属性

    下面是关于JSP JavaBean的setProperty属性的完整攻略。 什么是JSP JavaBean的setProperty属性? JSP JavaBean的setProperty属性,是指在JSP页面中,对JavaBean的属性进行设置的操作。使用setProperty属性,可以在JSP页面中为JavaBean的属性赋值,并更新JavaBean中属性…

    Java 2023年6月15日
    00
  • Springmvc模式上传和下载与enctype对比

    SpringMVC是一款开源的轻量级Web框架,支持MVC(Model-View-Controller)模式,以及RESTful风格的编程。SpringMVC提供了一个Spring MVC文件上传和下载的处理器,可以处理文件上传和下载的请求。关于SpringMVC模式的上传和下载,我们重点讲解一下enctype对比。 enctype 首先,我们需要明白enc…

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