gpt4 book ai didi

java - 使用 Spring Boot 设置无状态身份验证

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:40:46 27 4
gpt4 key购买 nike

我正在使用最新版本的 Spring Boot,我正在尝试设置 StatelessAuthenticaion。到目前为止,我一直在阅读的教程非常模糊,我不确定自己做错了什么。我使用的教程是...

http://technicalrex.com/2015/02/20/stateless-authentication-with-spring-security-and-jwt/

我的设置的问题是,似乎一切都在正常运行,除了 TokenAuthenticationService::addAuthentication 从未被调用,所以我的 token 从未被设置,因此当 TokenAuthenticationService::getAuthentication 被调用,因此即使我成功登录也会返回 401(因为从未调用 addAuthentication 来设置 header 中的 token )。我正在尝试寻找一种添加 TokenAuthenticationService::addAuthentication 的方法,但我发现这很困难。

在教程中,他将类似于 WebSecurityConfig::UserDetailsS​​ervice.userService 的内容添加到 auth.userDetailsS​​ervice() 中。我遇到的唯一问题是当我这样做,它会抛出 CastingErrorException。它仅在我使用 UserDetailsS​​ervice customUserDetailsS​​ervice 时有效...

网络安全配置

package app.config;

import app.repo.User.CustomUserDetailsService;
import app.security.RESTAuthenticationEntryPoint;
import app.security.RESTAuthenticationFailureHandler;
import app.security.RESTAuthenticationSuccessHandler;
import app.security.TokenAuthenticationService;
import app.security.filters.StatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

private static PasswordEncoder encoder;
private final TokenAuthenticationService tokenAuthenticationService;

private final CustomUserDetailsService userService;

@Autowired
private UserDetailsService customUserDetailsService;

@Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;

public WebSecurityConfig() {
this.userService = new CustomUserDetailsService();
tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", userService);
}

@Autowired
public void configureAuth(AuthenticationManagerBuilder auth,DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}

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

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").authenticated();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().defaultSuccessUrl("/").successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler);
//This is ho
http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);

}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}

@Bean
@Override
public CustomUserDetailsService userDetailsService() {
return userService;
}

@Bean
public TokenAuthenticationService tokenAuthenticationService() {
return tokenAuthenticationService;
}
}

TokenAuthenticationService 成功调用了getAuthentication 方法,但在我阅读的教程中,没有正确解释如何调用 addAuthentication

token 认证服务

package app.security;

import app.repo.User.CustomUserDetailsService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;

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

public class TokenAuthenticationService {


private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN";

private final TokenHandler tokenHandler;
//This is called in my WebSecurityConfig() constructor
public TokenAuthenticationService(String secret, CustomUserDetailsService userService) {
tokenHandler = new TokenHandler(secret, userService);
}

public void addAuthentication(HttpServletResponse response, UserAuthentication authentication) {
final UserDetails user = authentication.getDetails();
response.addHeader(AUTH_HEADER_NAME, tokenHandler.createTokenForUser(user));
}

public Authentication getAuthentication(HttpServletRequest request) {
final String token = request.getHeader(AUTH_HEADER_NAME);
if (token != null) {
final UserDetails user = tokenHandler.parseUserFromToken(token);
if (user != null) {
return new UserAuthentication(user);
}
}
return null;
}
}

token 处理器

package app.security;

import app.repo.User.CustomUserDetailsService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;

public final class TokenHandler {

private final String secret;
private final CustomUserDetailsService userService;

public TokenHandler(String secret, CustomUserDetailsService userService) {
this.secret = secret;
this.userService = userService;
}

public UserDetails parseUserFromToken(String token) {
String username = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
return userService.loadUserByUsername(username);
}

public String createTokenForUser(UserDetails user) {
return Jwts.builder()
.setSubject(user.getUsername())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
}

在我的 WebServiceConfig 中。我添加以下内容

http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);

它调用以下类作为过滤器。它获得了身份验证,但没有实际添加它的地方。

StatelessAuthenticationFilter

package app.security.filters;

import app.security.TokenAuthenticationService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
* Created by anthonygordon on 11/17/15.
*/
public class StatelessAuthenticationFilter extends GenericFilterBean {

private final TokenAuthenticationService authenticationService;

public StatelessAuthenticationFilter(TokenAuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
Authentication authentication = authenticationService.getAuthentication(httpRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication(null);
}
}

以下类是在 TokenAuthenticationService::addAuthentication

中传递的内容

用户身份验证

package app.security;

import app.repo.User.User;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class UserAuthentication implements Authentication {

private final UserDetails user;
private boolean authenticated = true;

public UserAuthentication(UserDetails user) {
this.user = user;
}

@Override
public String getName() {
return user.getUsername();
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}

@Override
public Object getCredentials() {
return user.getPassword();
}

@Override
public UserDetails getDetails() {
return user;
}

@Override
public Object getPrincipal() {
return user.getUsername();
}

@Override
public boolean isAuthenticated() {
return authenticated;
}

@Override
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
}

就是这样......

我的解决方案(但需要帮助)...

我的解决方案是在我的成功处理程序中设置 TokenAuthenticationService::addAuthentication 方法...唯一的问题是教程将类 TokenAuthenticationService 添加到 WebServiceConfig类(class)。那是唯一可以访问的地方。如果有办法在我的 successHandler 中获取它,我也许可以设置 token 。

package app.security;

import app.controllers.Requests.TriviaResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by anthonygordon on 11/12/15.
*/
@Component
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
TriviaResponse tresponse = new TriviaResponse();
tresponse.setMessage("You have successfully logged in");
String json = ow.writeValueAsString(tresponse);
response.getWriter().write(json);
clearAuthenticationAttributes(request);
}
}

最佳答案

当用户首次提供登录凭据时,您必须自己调用 TokenAuthenticationService.addAuthentication()

本教程在用户使用其 Google 帐户成功登录后调用 GoogleAuthorizationResponseServlet 中的 addAuthentication()。这是相关代码:

private String establishUserAndLogin(HttpServletResponse response, String email) {
// Find user, create if necessary
User user;
try {
user = userService.loadUserByUsername(email);
} catch (UsernameNotFoundException e) {
user = new User(email, UUID.randomUUID().toString(), Sets.<GrantedAuthority>newHashSet());
userService.addUser(user);
}

// Login that user
UserAuthentication authentication = new UserAuthentication(user);
return tokenAuthenticationService.addAuthentication(response, authentication);
}

如果您已经有身份验证成功处理程序,那么我认为您走在正确的轨道上,您需要从那里调用 TokenAuthenticationService.addAuthentication()。将 tokenAuthenticationService bean 注入(inject)到您的处理程序中,然后开始使用它。如果您的成功处理程序最终不是 Spring bean,那么您可以通过调用 WebApplicationContextUtils.getRequiredWebApplicationContext.getBean(TokenAuthenticationService.class) 显式查找 tokenAuthenticationService

还有一个 issue在本教程的 GitHub 存储库中,它将解决用户提供的初始登录与所有后续请求中发生的无状态身份验证之间的混淆。

关于java - 使用 Spring Boot 设置无状态身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33784776/

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