gpt4 book ai didi

spring-boot - 在Spring Boot应用程序中配置安全性

转载 作者:行者123 更新时间:2023-12-03 14:29:40 25 4
gpt4 key购买 nike

我正在将应用程序升级到Spring Boot 2.0.3

但是我的登录请求是未经授权的:

curl -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:8080/api/users/login" -X POST -d "{ \"email\" : \"myemail@somedomain.com\", \"password\" : \"xxxxx\" }" -i

响应是一个 401 Unauthorized access. You failed to authenticate

它由我的自定义入口点给出:
@Component
public final class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

private static Logger logger = LoggerFactory.getLogger(RESTAuthenticationEntryPoint.class);

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
logger.debug("Security - RESTAuthenticationEntryPoint - Entry point 401");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized access. You failed to authenticate.");
}

@Override
public void afterPropertiesSet() throws Exception {
setRealmName("User REST");
super.afterPropertiesSet();
}

}

调试器显示未调用 authenticateCustomAuthenticationProvider方法,因为我期望它是:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

@Autowired
CredentialsService credentialsService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
User user = null;
try {
user = credentialsService.findByEmail(new EmailAddress(email));
} catch (IllegalArgumentException e) {
throw new BadCredentialsException("The login " + email + " and password could not match.");
}
if (user != null) {
if (credentialsService.checkPassword(user, password)) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new UsernamePasswordAuthenticationToken(email, password, grantedAuthorities);
} else {
throw new BadCredentialsException("The login " + user.getEmail() + " and password could not match.");
}
}
throw new BadCredentialsException("The login " + authentication.getPrincipal() + " and password could not match.");
}

@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}

}

但是过滤器被执行,并且找到了一个空 token :
@Component
public class AuthenticationFromTokenFilter extends OncePerRequestFilter {

@Autowired
private TokenAuthenticationService tokenAuthenticationService;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
tokenAuthenticationService.authenticateFromToken(request);
chain.doFilter(request, response);
}

}

@Service
public class TokenAuthenticationServiceImpl implements TokenAuthenticationService {

private static Logger logger = LoggerFactory.getLogger(TokenAuthenticationServiceImpl.class);

private static final long ONE_WEEK = 1000 * 60 * 60 * 24 * 7;
private static final String TOKEN_URL_PARAM_NAME = "token";

@Autowired
private ApplicationProperties applicationProperties;

@Autowired
private UserDetailsService userDetailsService;

public void addTokenToResponseHeader(HttpHeaders headers, String username) {
String token = buildToken(username);
headers.add(CommonConstants.AUTH_HEADER_NAME, token);
}

public void addTokenToResponseHeader(HttpServletResponse response, Authentication authentication) {
String username = authentication.getName();
if (username != null) {
String token = buildToken(username);
response.addHeader(CommonConstants.AUTH_HEADER_NAME, token);
}
}

private String buildToken(String username) {
String token = null;
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null) {
Date expirationDate = new Date(System.currentTimeMillis() + ONE_WEEK);
token = CommonConstants.AUTH_BEARER + " " + Jwts.builder().signWith(HS256, getEncodedPrivateKey()).setExpiration(expirationDate).setSubject(userDetails.getUsername()).compact();
}
return token;
}

public Authentication authenticateFromToken(HttpServletRequest request) {
String token = extractAuthTokenFromRequest(request);
logger.debug("The request contained the JWT token: " + token);
if (token != null && !token.isEmpty()) {
try {
String username = Jwts.parser().setSigningKey(getEncodedPrivateKey()).parseClaimsJws(token).getBody().getSubject();
if (username != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("Security - The filter authenticated fine from the JWT token");
}
} catch (SignatureException e) {
logger.info("The JWT token " + token + " could not be parsed.");
}
}
return null;
}

private String extractAuthTokenFromRequest(HttpServletRequest request) {
String token = null;
String header = request.getHeader(CommonConstants.AUTH_HEADER_NAME);
if (header != null && header.contains(CommonConstants.AUTH_BEARER)) {
int start = (CommonConstants.AUTH_BEARER + " ").length();
if (header.length() > start) {
token = header.substring(start - 1);
}
} else {
// The token may be set as an HTTP parameter in case the client could not set it as an HTTP header
token = request.getParameter(TOKEN_URL_PARAM_NAME);
}
return token;
}

private String getEncodedPrivateKey() {
String privateKey = applicationProperties.getAuthenticationTokenPrivateKey();
return Base64.getEncoder().encodeToString(privateKey.getBytes());
}

}

我的安全配置是:
@Configuration
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security", "com.thalasoft.user.rest.filter" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private AuthenticationFromTokenFilter authenticationFromTokenFilter;

@Autowired
private SimpleCORSFilter simpleCORSFilter;

@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;

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

@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.authenticationProvider(new CustomAuthenticationProvider());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class)
.headers().cacheControl().disable().frameOptions().disable()
.and()
.userDetailsService(userDetailsService)
.authorizeRequests()
.antMatchers(RESTConstants.SLASH + UserDomainConstants.USERS + RESTConstants.SLASH + UserDomainConstants.LOGIN).permitAll()
.antMatchers(RESTConstants.SLASH + RESTConstants.ERROR).permitAll()
.antMatchers("/**").hasRole(UserDomainConstants.ROLE_ADMIN).anyRequest().authenticated();
}

}

用户详细信息服务是:
@Component
public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
private CredentialsService credentialsService;

@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && !username.isEmpty()) {
User user = credentialsService.findByEmail(new EmailAddress(username));
if (user != null) {
return new UserDetailsWrapper(user);
}
}
throw new UsernameNotFoundException("The user " + username + " was not found.");
}

}

为什么自定义身份验证提供程序不对用户名和密码进行身份验证?

更新:
我在这个 guide中读到了一些有趣和令人困惑的东西
Note that the AuthenticationManagerBuilder is @Autowired into a method in a @Bean - that is what makes it build the global (parent) AuthenticationManager. In contrast if we had done it this way (using an @Override of a method in the configurer) then the AuthenticationManagerBuilder is only used to build a "local" AuthenticationManager, which is a child of the global one. In a Spring Boot application you can @Autowired the global one into another bean, but you can’t do that with the local one unless you explicitly expose it yourself.

那么,我使用 configure方法设置 authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);有什么问题吗?
除了上面的配置,我尝试了以下配置:
@Autowired
public void initialize(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
}

但是,它仍然没有根据请求执行自定义身份验证提供程序。

我也尝试过使用过滤器,如下所示:
http.addFilterAfter(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class);

而不是 addFilterBefore,但它并没有改变问题。

最佳答案

在WebSecurityConfiguration里面的configure(HttpSecurity http)方法:

http.authorizeRequests().antMatchers("/api/users/login").permitAll(); 
http.authorizeRequests().anyRequest().authenticated();

以相同的顺序添加。

说明:登录和注销请求应被允许,而无需任何身份验证

一个有效的示例配置方法是:
http.formLogin().disable().logout().disable().httpBasic().disable();

http.authorizeRequests().antMatchers("/logout", "/login", "/").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.addFilterBefore(new SomeFilter(), SecurityContextHolderAwareRequestFilter.class);
http.addFilterBefore(new CORSFilter(env), ChannelProcessingFilter.class);
http.addFilterBefore(new XSSFilter(),CORSFilter.class);

关于spring-boot - 在Spring Boot应用程序中配置安全性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51514561/

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