gpt4 book ai didi

使用 JWT 的 Spring Security 总是返回 401 未经授权

转载 作者:行者123 更新时间:2023-12-04 13:02:38 26 4
gpt4 key购买 nike

1

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Resource(name = "userService")
private UserDetailsService userDetailsService;

@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;

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

@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
/*auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select login as principal, mot_de_passe as credentials, flag_compte_actif as enabled from utilisateur where login = ?")
.authoritiesByUsernameQuery("SELECT utilisateur.login as principal, profil.designation as role FROM utilisateur INNER JOIN user_profil ON utilisateur.id_user = user_profil.iduserpk INNER JOIN profil ON user_profil.idprofilpk = profil.id_profil WHERE utilisateur.login = ? ")
.rolePrefix("ROLE_");

auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());*/
auth.inMemoryAuthentication()
.withUser("admin")
.password("password")
.roles("Administrateur");
}

@Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Akal configure method begin");
//http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);

http.cors().and()
.csrf().disable().
authorizeRequests()
.antMatchers("/token/generate").permitAll()
.anyRequest().authenticated()
.and().formLogin().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
System.out.println("Akal configure method");
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);


}

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

@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}

}

2
@RestController
@CrossOrigin("*")
public class AuthenticationController {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Autowired
private UtilisateurRepository userRepo;

@PostMapping(value = "/token/generate")
public ResponseEntity<?> register(@RequestBody LoginUser loginUser) throws AuthenticationException {
System.out.println("We're in man!");
final Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginUser.getUsername(),
loginUser.getPassword()
)
);
System.out.println("(Username, Password): (" + loginUser.getUsername() + ", " + loginUser.getPassword() + ")");
SecurityContextHolder.getContext().setAuthentication(authentication);
final Utilisateur user = userRepo.findByLogin(loginUser.getUsername());
final String token = jwtTokenUtil.generateToken(user);
System.out.println("Token Controller Access=> Token Generated: " + token);
return ResponseEntity.ok(new AuthToken(token));
}

}

3
public class AuthToken {

private String token;

public AuthToken(){

}

public AuthToken(String token){
this.token = token;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

}

4
public class CorsFilter implements Filter {

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("Filtering on...........................................................");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
//response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers");

chain.doFilter(req, res);
}

public void init(FilterConfig filterConfig) {}

public void destroy() {}

}

5
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}

6
public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String header = req.getHeader("Authorization");
String username = null;
String authToken = null;
if (header != null && header.startsWith("Bearer ")) {
authToken = header.replace("Bearer ","");
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (ExpiredJwtException e) {
logger.warn("the token is expired and not valid anymore", e);
} catch(SignatureException e){
logger.error("Authentication Failed. Username or Password not valid.");
}
} else {
logger.warn("couldn't find bearer string, will ignore the header");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

UserDetails userDetails = userDetailsService.loadUserByUsername(username);

if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}

chain.doFilter(req, res);
}
}

7
@Component
public class JwtTokenUtil implements Serializable {

static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "secret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";


public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}

public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}

public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}

private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}

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

public String generateToken(Utilisateur user) {
return doGenerateToken(user.getLogin());
}

private String doGenerateToken(String subject) {

Claims claims = Jwts.claims().setSubject(subject);
claims.put("scopes", Arrays.asList(new SimpleGrantedAuthority("ROLE_Administrateur")));

return Jwts.builder()
.setClaims(claims)
.setIssuer("http://devglan.com")
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}

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

}

8
public class LoginUser {

private String username;
private String password;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

我只贴了这2个类,因为老实说我有8个配置类,读起来会很痛苦!它也是自定义的 JWT 代码,但如果有必要全部发布,请告诉我。

除此之外,我就是无法确定问题所在! Spring 控制台没有显示任何错误,当我尝试从 Postman 请求时,结果如下:
result

当我从浏览器运行请求时,它没有说 401,它只是说错误的凭据,即使它们是正确的,我也尝试了数十个用户以确保

谢谢!

更新:我发布了其余的类(class),因为问题可能与这两个无关

最佳答案

在 Spring Security 5 中,如果您使用的是 auth.inMemoryAuthentication() ,您将无法使用 BCryptPasswordEncoderStandardPasswordEncoder .您必须使用自己的 UserDetailsService以获取用户和密码。或者,如果您需要测试您的代码,只需返回 NoOpPasswordEncoder.getInstance()在您的 passwordEncoder()方法

SecurityConfig.class

    @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AccountService accountService; //your own implementation of UserDetailsService

....

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(true)
.userDetailsService(accountService)
.passwordEncoder(passwordEncoder());
}

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

....

}

AccountService.class
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AccountService implements UserDetailsService {

@Autowired
private AccountRepository accountRepository; //Your database repository

@Autowired
private PasswordEncoder passwordEncoder;

@PostConstruct
protected void initialize() {
save(new Account("user", "demo", "ROLE_USER"));
save(new Account("admin", "admin", "ROLE_ADMIN"));
}

@Transactional
public Account save(Account account) {
account.setPassword(passwordEncoder.encode(account.getPassword()));
accountRepository.save(account);
return account;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountRepository.findOneByEmail(username);
if(account == null) {
throw new UsernameNotFoundException("user not found");
}
return createUser(account);
}

public void signin(Account account) {
SecurityContextHolder.getContext().setAuthentication(authenticate(account));
}

private Authentication authenticate(Account account) {
return new UsernamePasswordAuthenticationToken(createUser(account), null, Collections.singleton(createAuthority(account)));
}

private User createUser(Account account) {
return new User(account.getEmail(), account.getPassword(), Collections.singleton(createAuthority(account)));
}

private GrantedAuthority createAuthority(Account account) {
return new SimpleGrantedAuthority(account.getRole());
}

}

Account.class
@SuppressWarnings("serial")
@Entity
@Table(name = "account")
public class Account implements java.io.Serializable {

@Id
@GeneratedValue
private Long id;

@Column(unique = true)
private String email;

@JsonIgnore
private String password;

private String role = "ROLE_USER";

private Instant created;

protected Account() {

}

public Account(String email, String password, String role) {
this.email = email;
this.password = password;
this.role = role;
this.created = Instant.now();
}

public Long getId() {
return id;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getRole() {
return role;
}

public void setRole(String role) {
this.role = role;
}

public Instant getCreated() {
return created;
}
}

关于使用 JWT 的 Spring Security 总是返回 401 未经授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52028457/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com