Spring Security+JWT实现认证与授权的实现

下面我就来详细讲解一下“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. 创建一个自定义的UserDetailsService,用于查询用户信息:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    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);
    }
}
  1. 创建一个JwtUtils工具类,用于生成Token、解析Token等操作:
@Component
public class JwtUtils {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private int expiration;

    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() + expiration * 1000))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public String getUsernameFromJwtToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
    }

    public boolean validateJwtToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException e) {
            logger.error("Invalid JWT signature: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            logger.error("Invalid JWT token: {}", e.getMessage());
        } catch (ExpiredJwtException e) {
            logger.error("JWT token is expired: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            logger.error("JWT token is unsupported: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            logger.error("JWT claims string is empty: {}", e.getMessage());
        }

        return false;
    }
}

二、完成认证与授权实现

在完成了上面的准备工作之后,我们可以开始完成认证与授权的实现了。

  1. 创建一个JwtTokenFilter过滤器,用于拦截请求并验证Token:
@Component
public class JwtTokenFilter 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. 创建一个JwtAuthEntryPoint,用于处理未经过授权的请求:
@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
    }
}
  1. 在SecurityConfig中进行配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtAuthEntryPoint unauthorizedHandler;

    @Bean
    public JwtTokenFilter authenticationJwtTokenFilter() {
        return new JwtTokenFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

三、示例1:实现用户登录

我们来看一个实现用户登录的示例:

  1. 创建一个AuthService用于处理用户登录请求:
@Service
public class AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    public JwtResponse authenticateUser(LoginRequest loginRequest) {

        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtUtils.generateJwtToken(authentication);

        UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
        List<String> roles = userDetails.getAuthorities().stream()
                .map(item -> item.getAuthority())
                .collect(Collectors.toList());

        return new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail(), roles);
    }
}
  1. 创建一个Controller,用于处理登录请求:
@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private AuthService authService;

    @PostMapping("/signin")
    public ResponseEntity<?> authenticateUser(@Validated @RequestBody LoginRequest loginRequest) {

        JwtResponse jwtResponse = authService.authenticateUser(loginRequest);

        return ResponseEntity.ok(jwtResponse);
    }
}

四、示例2:实现角色权限控制

我们来看另一个示例,实现角色权限控制。

  1. 创建一个SecuredController用于测试用户是否具有角色权限:
@RestController
@RequestMapping("/api")
public class SecuredController {

    @GetMapping("/test")
    @PreAuthorize("hasRole('USER')")
    public String userAccess() {
        return "User Content.";
    }

    @GetMapping("/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public String adminAccess() {
        return "Admin Board.";
    }
}
  1. 在RoleEnum中定义角色:
public enum RoleEnum {

    ROLE_USER,
    ROLE_ADMIN
}
  1. 在UserDetailsImpl中重写getAuthorities方法:
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName().name())).collect(Collectors.toList());
}

五、总结

通过上面的几个步骤,我们实现了基于Spring Security和JWT的认证与授权实现,并且还给出了两个示例来演示如何实现用户登录和角色权限控制。希望这篇文章能够对你有所帮助。

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

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

相关文章

  • 深入了解Java8中的时区日期时间

    关于“深入了解Java8中的时区日期时间”的攻略,我将从以下几个方面进行详细讲解: 时区概念介绍 Java8中的时区 日期时间的表示和操作 时区转换和格式化 时区概念介绍 时区是一个地球上的地区,为方便起见,划分为24个标准时区,每个时区以相对于格林威治标准时间的小时数进行标记。时区与地球上的经度有密切关系,通常是基于一个参考点来描述小时数。例如,北京的时区…

    Java 2023年5月20日
    00
  • Java开发环境配置教程(win7 64bit)

    Java开发环境配置教程(win7 64bit) 下载JDK安装包 首先需要进入Oracle官网下载JDK安装包,进入https://www.oracle.com/java/technologies/javase-downloads.html进行下载。 安装JDK及设置环境变量 安装JDK之前需要检查系统是否已安装Java(JRE)。如果已经安装,需要先卸载…

    Java 2023年5月23日
    00
  • GSON实现Java对象与JSON格式对象相互转换的完全教程

    GSON实现Java对象与JSON格式对象相互转换的完全教程 什么是GSON GSON是Google提供的用来在Java对象和JSON数据之间进行序列化和反序列化的Java库。GSON可以将Java对象转化为JSON字符串,也可以将JSON字符串转化为相应的Java对象。 准备工作 在使用GSON之前,您需要做以下准备工作: 下载GSON库 可以通过Mave…

    Java 2023年5月26日
    00
  • Java编程Retry重试机制实例详解

    Java编程Retry重试机制实例详解 在实际工作中,我们经常会遇到一些不稳定的网络或服务,如果我们在请求时遇到了异常,通常需要进行重试。这时,Retry重试机制能够有效保证我们的请求能够成功返回。这篇文章就来详细讲解Java编程Retry重试机制的实例。 Retry重试机制是什么 Retry重试机制是指我们在请求某个服务时,如果第一次请求失败了,我们可以再…

    Java 2023年5月27日
    00
  • JavaWeb中的路径问题解读

    JavaWeb中的路径问题解读 在JavaWeb开发中,路径问题一直是困扰初学者的难点之一,本文将深入剖析JavaWeb中的路径问题,让读者对JavaWeb中的路径有更全面的理解。 1. 路径的种类 在JavaWeb中,常见的路径种类包括:绝对路径、相对路径、虚拟路径和物理路径。接下来分别进行讲解。 1.1 绝对路径 绝对路径是指从硬盘根目录开始的完整路径,…

    Java 2023年6月16日
    00
  • JavaSpringBoot报错“NotAcceptableException”的原因和处理方法

    原因 “NotAcceptableException” 错误通常是以下原因引起的: 请求头问题:如果请求头中包含不受支持的媒体类型,则可能会出现此错误。在这种情况下,需要检查请求头并确保它们正确。 响应类型问题:如果响应类型不受支持,则可能会出现此错误。在这种情况下,需要检查响应类型并确保它们正确。 控制器问题:如果控制器中存在问题,则可能会出现此错误。在这…

    Java 2023年5月4日
    00
  • 详解在Spring Boot中使用Mysql和JPA

    我将为你详细讲解“详解在Spring Boot中使用Mysql和JPA”的完整攻略。 准备工作 在开始时,您需要以下软件和环境:- JDK >= 1.8- Spring Boot >= 2.0.0.RELEASE- MySQL- Maven 创建Spring Boot项目 首先,您需要创建一个Spring Boot项目。您可以使用Spring官网…

    Java 2023年5月20日
    00
  • SpringMVC拦截器快速掌握上篇

    下面是关于“SpringMVC拦截器快速掌握上篇”的完整攻略,希望能够对您有所帮助。 什么是SpringMVC拦截器 在SpringMVC框架中,拦截器是一个非常重要的组件,它可以让我们在请求到达Controller之前或者返回结果给客户端之前进行一些统一处理,比如日志记录、权限校验等。 SpringMVC拦截器的配置 配置SpringMVC拦截器很简单,只…

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