Spring 安全用户无法转换为 class 用户

Spring security User cannot be casted to class user

首先请记住我是一个 Java 菜鸟,这对我来说都是未开发的领域。

我遵循了一个指南(大约 6 个月大)来实现 spring 安全性,我从未找到配置为专门与单独的前端层一起工作的指南。

在实施令牌之前,每一步都有效,我吐出了这个错误:

class org.springframework.security.core.userdetails.User cannot be cast to class com.example.springboot.model.User

我在这里看到了其他类似的帖子,尽管他们讨论的不同

例如

  1. - 这讨论了不返回实体

  2. - 在 JwtAuthenticationFilter class

    中讨论错误的导入语句 org.springframework.security.core.userdetails.User

首先,我使用 org.springframework.security.core.userdetails.userDetails(类似于指南作者)

其次,我在三个实例中概述了此提供商(2 userDetails 和 1 userDetailsService

1x userDetailsJWTAuthenticationFilter

1x userDetailsServiceJWTAuthenticationFilter

1x userDetailsJWTTokenHelper

这是终点:

    @PostMapping("/auth/login")
    public ResponseEntity<?> login(@RequestBody AuthenticationRequest authenticationRequest) throws InvalidKeySpecException, NoSuchAlgorithmException {

        final Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
                authenticationRequest.getUserName(), authenticationRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);

        User user=(User)authentication.getPrincipal(); // crashes here
        String jwtToken=jWTTokenHelper.generateToken(user.getUsername());

        LoginResponse response=new LoginResponse();
        response.setToken(jwtToken);

        return ResponseEntity.ok(response);
    }

returns 注释行上的错误,进一步钻取并查看以下 class,它命中第一个 if 语句(我认为它不是 null?)

然后转到 filterChain.doFilter 并崩溃

JWTAuthenticationFilter如下图:

package com.example.springboot.config;
import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.web.filter.OncePerRequestFilter;

public class JWTAuthenticationFilter extends OncePerRequestFilter {

    private UserDetailsService userDetailsService;
    private JWTTokenHelper jwtTokenHelper;

    public JWTAuthenticationFilter(UserDetailsService userDetailsService, JWTTokenHelper jwtTokenHelper) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenHelper = jwtTokenHelper;

    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String authToken = jwtTokenHelper.getToken(request);
        if (null != authToken) { // fails this check
            String userName = jwtTokenHelper.getUsernameFromToken(authToken);
            if (null != userName) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
                if (jwtTokenHelper.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetails(request));

                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        filterChain.doFilter(request, response); // returns error here
    }
}

JWTTokenHelper 如下图:

package com.example.springboot.config;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JWTTokenHelper {

    @Value("${jwt.auth.app}")
    private String appName;

    @Value("${jwt.auth.secret_key}")
    private String secretKey;

    @Value("${jwt.auth.expires_in}")
    private int expiresIn;

    private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;

    public JWTTokenHelper(String appName, String secretKey, int expiresIn, SignatureAlgorithm SIGNATURE_ALGORITHM) {
        this.appName = appName;
        this.secretKey = secretKey;
        this.expiresIn = expiresIn;
        this.SIGNATURE_ALGORITHM = SIGNATURE_ALGORITHM;
    }

    public JWTTokenHelper() { }

    private Claims getAllClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    public String getUsernameFromToken(String token) {
        String username;
        try {
            final Claims claims = this.getAllClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    public String generateToken(String username) throws InvalidKeySpecException, NoSuchAlgorithmException {
        return Jwts.builder()
                .setIssuer( appName )
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(generateExpirationDate())
                .signWith( SIGNATURE_ALGORITHM, secretKey )
                .compact();
    }

    private Date generateExpirationDate() {
        return new Date(new Date().getTime() + expiresIn * 1000);
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (
                username != null &&
                        username.equals(userDetails.getUsername()) &&
                        !isTokenExpired(token)
        );
    }

    public boolean isTokenExpired(String token) {
        Date expireDate=getExpirationDate(token);
        return expireDate.before(new Date());
    }


    private Date getExpirationDate(String token) {
        Date expireDate;
        try {
            final Claims claims = this.getAllClaimsFromToken(token);
            expireDate = claims.getExpiration();
        } catch (Exception e) {
            expireDate = null;
        }
        return expireDate;
    }


    public Date getIssuedAtDateFromToken(String token) {
        Date issueAt;
        try {
            final Claims claims = this.getAllClaimsFromToken(token);
            issueAt = claims.getIssuedAt();
        } catch (Exception e) {
            issueAt = null;
        }
        return issueAt;
    }

    public String getToken( HttpServletRequest request ) {
        String authHeader = getAuthHeaderFromHeader( request );
        if ( authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }

        return null;
    }

    public String getAuthHeaderFromHeader( HttpServletRequest request ) {
        return request.getHeader("Authorization");
    }
}

对于描述为“简单实现”的内容,此实现相当长(14 classes),我不知道是哪一部分导致了错误。非常感谢任何建议! :)

编辑:

看了更多之后,get token 方法似乎在这里失败了:

编辑2: 自定义 userDetailsS​​ervice class:

package com.example.springboot.service;

import com.example.springboot.model.User;
import com.example.springboot.repository.UserDetailsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserService implements UserDetailsService {

    @Autowired
    UserDetailsRepository userDetailsRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDetailsRepository.findByUserName(username);
        if (user != null){ return user; }
        else{ throw new UsernameNotFoundException("Incorrect username:" + username); }
    }
}

根据@Marcus Hert da Coregio 的建议

org.springframework.security.core.userdetails.User,这是您在 UserDetailsS​​ervice 中返回的实现。但是,在您的控制器中,您正试图将 Spring 安全的实现强制转换为您的 com.example.springboot.model.User。请看一下进口

import org.springframework.security.core.userdetails.User;

尽管本指南遇到了其他问题