Spring Security代码实现JWT接口权限授予与校验功能

为了实现JWT接口权限授予与校验功能,我们需要以下步骤:

1. 添加Spring Security和JWT依赖

Spring Security是一个现成的身份验证和授权框架,而JWT是一种安全性较高的身份认证方式。因此,我们需要添加相关依赖来支持这些功能。可以在Maven或Gradle中添加以下依赖:

<dependencies>
    ...
    <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>
    ...
</dependencies>

2. 实现UserDetailsService

如果我们要使用Spring Security来实现身份验证和授权,那么我们需要实现一个UserDetailsService接口来加载用户信息。可以通过实现loadUserByUsername方法来返回一个UserDetails对象,Spring Security将使用该对象进行身份验证。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) {
        // 从数据库或其他数据源加载用户信息
        User user = userRepository.findByUsername(username);

        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }

        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                new ArrayList<>());
    }
}

3. 实现JWT Token生成和校验

我们需要实现一个JWT Token工具类,用于生成和校验JWT Token。我们可以使用JJWT库来生成和解析JWT Token。

@Component
public class JwtTokenUtil {

    private static final String SECRET_KEY = "secret";

    public String generateToken(UserDetails userDetails) {
        // 设置Token过期时间为10小时
        long expirationTime = 36000000;

        return Jwts.builder()
                .setSubject(userDetails.getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public boolean validateToken(String token, UserDetails userDetails) {
        String username = extractUsername(token);

        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = extractExpiration(token);
        return expiration.before(new Date());
    }

    private Date extractExpiration(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
    }

    private String extractUsername(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
    }
}

4. 实现JWT过滤器

我们需要实现一个过滤器,用于在HTTP请求中解析JWT Token并在Spring Security中进行身份验证和授权。我们可以实现一个JwtRequestFilter类来处理此过程。

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            username = jwtTokenUtil.extractUsername(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());

                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }

        chain.doFilter(request, response);
    }
}

5. 配置Spring Security

我们需要配置Spring Security来允许对某些URL进行特殊的身份验证和授权。可以通过扩展WebSecurityConfigurerAdapter来实现此操作。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests().antMatchers("/authenticate").permitAll().
                anyRequest().authenticated().and().
                exceptionHandling().and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

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

示例1

以下示例演示了如何在Spring Boot中使用JWT进行身份验证和授权。我们将获取JWT Token并在受保护的REST API上使用它来验证用户的身份。

@RestController
public class UserController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/authenticate")
    public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest)
            throws Exception {

        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
                    authenticationRequest.getUsername(), authenticationRequest.getPassword()));
        } catch (BadCredentialsException e) {
            throw new Exception("Incorrect username or password", e);
        }

        final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());

        final String jwt = jwtTokenUtil.generateToken(userDetails);

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

    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.findAll();
    }

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/users")
    public void addUser(@RequestBody User user) {
        userService.save(user);
    }
}

在上面的示例中,我们首先使用AuthenticationManager来进行身份验证。如果身份验证成功,将生成一个JWT Token并将其添加到响应中。

该代码还包括一个受保护的REST API,其中用户需要具有ADMIN角色才能访问。我们可以使用PreAuthorize注释来限制对此API的访问。在链式调用中使用了anyRequest().authenticated()来保护未受保护的REST端点,而permitAll()可用于允许所有用户获取JWT Token。

示例2

以下示例演示了如何在Spring Security中使用JWT进行授权和校验用户的身份。

@RestController
public class UserController {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @GetMapping("/users")
    public List<User> getUsers(HttpServletRequest request) {
        String authorizationHeader = request.getHeader("Authorization");
        String jwtToken = authorizationHeader.substring(7);

        JwtClaims jwtClaims = Jwts.parser().setSigningKey(JwtTokenUtil.SECRET_KEY).parseClaimsJws(jwtToken).getBody();
        String username = jwtClaims.getSubject();

        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
            return userService.findAll();
        } else {
            throw new UnauthorizedException("Invalid token");
        }
    }
}

在上面的示例中,我们从HTTP头中获取JWT Token,解析它并根据其内容加载用户信息。如果JWT Token是有效的,并且对当前请求的用户有授权,则我们可以执行请求。

我们还可以使用JwtTokenUtil来捕获JWToken并调用validateToken进行验证。如果验证成功,我们可以继续与请求。如果JWToken无效,则会抛出异常。

这里只是一个简单的示例,实际情况下可以根据需要进行更多的自定义授权和身份验证逻辑。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security代码实现JWT接口权限授予与校验功能 - Python技术站

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

相关文章

  • java 如何给对象中的包装类设置默认值

    Java中的包装类(Wrapper Class)是为了让基本数据类型(int、double、char等)具有面向对象的特性而出现的。在Java中,包装类和基本数据类型之间可以进行自动装箱和自动拆箱的转换,方便了编程的过程。在某些情况下,我们需要给对象中的包装类设置默认值,下面是详细讲解“Java 如何给对象中的包装类设置默认值”的攻略。 1. 给包装类设置初…

    Java 2023年5月26日
    00
  • JS版微信6.0分享接口用法分析

    下面我将详细讲解“JS版微信6.0分享接口用法分析”的完整攻略。 一、JS版微信6.0分享接口简介 JS版微信6.0分享接口是微信公众号提供的一种方式,允许网站开发者在网页端调用微信分享功能,从而使用户直接将网页内容分享到微信朋友圈、好友或者分组内的好友。 二、JS版微信6.0分享接口使用步骤 1. 引入JS文件 在HTML文件中的head标签内,加入如下代…

    Java 2023年5月26日
    00
  • 史上最全最强SpringMVC详细示例实战教程(图文)

    “史上最全最强SpringMVC详细示例实战教程(图文)”是一篇非常详细的SpringMVC教程,其中包含了众多实战示例,可以帮助初学者深入了解SpringMVC框架,掌握相关开发技术和实现方法。本文将详细讲解整篇教程的内容,包括主要内容、实现方法、示例说明等。 主要内容 “史上最全最强SpringMVC详细示例实战教程(图文)”主要涵盖以下内容: Spri…

    Java 2023年5月16日
    00
  • java实现动态数组

    下面是关于Java实现动态数组的完整攻略: 什么是动态数组? 动态数组,简称为ArrayList,是在Java中使用较为广泛的数据结构之一。它是一种可变数组,可以根据需要自动扩展数组的大小。与传统的数组不同,动态数组的大小是可以根据需求动态增长或者缩小的。 Java中动态数组的实现 在Java中,动态数组的实现是通过内部维护一个Object数组来实现。当需要…

    Java 2023年5月26日
    00
  • Java 中Map 的用法详解

    Java 中 Map 的用法详解 简介 Map 是 Java 中常见的一种数据结构,它存储了一组键值对,其中每个键都唯一对应一个值,而多个键可以对应同一个值。在 Map 中,通过键快速定位对应的值,相对于遍历数组或者列表来说,速度更快。在 Java 中,Map 接口有多个实现类,其中常用的有 HashMap 和 TreeMap。 常用方法介绍 1. put …

    Java 2023年5月26日
    00
  • ActiveMQ简单入门(新手必看篇)

    ActiveMQ简单入门(新手必看篇) ActiveMQ是一个流行的开源消息队列系统,它具有高可用性、高性能、多语言支持等诸多优点,被广泛应用于分布式系统的消息通信场景中。本篇文章将详细讲解ActiveMQ的入门步骤,帮助新手快速上手使用。 安装ActiveMQ 首先需要在官网(http://activemq.apache.org/)上下载ActiveMQ二…

    Java 2023年6月15日
    00
  • Java秒杀系统:web层详解

    Java秒杀系统:web层详解攻略 本文主要讲解Java秒杀系统的web层,包括前端页面、后台接口、安全性优化等方面。 一、前端页面设计 在秒杀系统中,前端页面的设计十分重要,直接决定了用户体验的好坏。以下是本系统的设计思路: 1. 登录页面 登录页面分为两个部分,一个是用户名、密码和验证码输入框,另一个是一个按钮,可以选择单击或使用快捷登录。通过JQuer…

    Java 2023年5月30日
    00
  • springboot 2.x整合mybatis实现增删查和批量处理方式

    下面是“springboot 2.x整合mybatis实现增删查和批量处理方式”的完整攻略。 准备工作 在开始整合之前,需要确保已经添加了Spring Boot和MyBatis的依赖。 先来看一下pom.xml文件: <dependencies> <!–Spring Boot相关依赖–> <dependency> &l…

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