gpt4 book ai didi

java - Spring Security - 记住我自定义服务 onLoginSuccess 未使用 oauth2 调用

转载 作者:行者123 更新时间:2023-12-02 00:42:02 25 4
gpt4 key购买 nike

我正在尝试使用 jHipster 生成的 webapp 实现记住我的功能。我正在更新一个旧的项目登录页面,其中会有一个记住我的复选框。

我遇到的问题是我正在实现的 RememberMeServices 不起作用。准确的说,没有调用onLoginSuccess方法,也没有进行持久化token的初始化。

然而,CustomPersistentRememberMeServices 的注销方法被调用。

我有一个自定义记住我的服务,定义如下:

@Service("rememberMeServices")
public class CustomPersistentRememberMeServices extends
AbstractRememberMeServices {

private final Logger log = LoggerFactory.getLogger(CustomPersistentRememberMeServices.class);

// Token is valid for one month
private static final int TOKEN_VALIDITY_DAYS = 31;

private static final int TOKEN_VALIDITY_SECONDS = 60 * 60 * 24 * TOKEN_VALIDITY_DAYS;

private static final int DEFAULT_SERIES_LENGTH = 16;

private static final int DEFAULT_TOKEN_LENGTH = 16;

private SecureRandom random;

@Inject
private PersistentTokenRepository persistentTokenRepository;

@Inject
private UserRepository userRepository;

@Inject
public CustomPersistentRememberMeServices(Environment env, org.springframework.security.core.userdetails
.UserDetailsService userDetailsService) {

super(env.getProperty("jhipster.security.rememberme.key"), userDetailsService);
random = new SecureRandom();
}

@Override
@Transactional
protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
HttpServletResponse response) {

PersistentToken token = getPersistentToken(cookieTokens);
String login = token.getUser().getLogin();

// Token also matches, so login is valid. Update the token value, keeping the *same* series number.
log.debug("Refreshing persistent login token for user '{}', series '{}'", login, token.getSeries());
token.setTokenDate(LocalDate.now());
token.setTokenValue(generateTokenData());
token.setIpAddress(request.getRemoteAddr());
token.setUserAgent(request.getHeader("User-Agent"));
try {
persistentTokenRepository.saveAndFlush(token);
addCookie(token, request, response);
} catch (DataAccessException e) {
log.error("Failed to update token: ", e);
throw new RememberMeAuthenticationException("Autologin failed due to data access problem", e);
}
return getUserDetailsService().loadUserByUsername(login);
}

@Override
protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication
successfulAuthentication) {

String login = successfulAuthentication.getName();

log.debug("Creating new persistent login for user {}", login);
PersistentToken token = userRepository.findOneByLogin(login).map(u -> {
PersistentToken t = new PersistentToken();
t.setSeries(generateSeriesData());
t.setUser(u);
t.setTokenValue(generateTokenData());
t.setTokenDate(LocalDate.now());
t.setIpAddress(request.getRemoteAddr());
t.setUserAgent(request.getHeader("User-Agent"));
return t;
}).orElseThrow(() -> new UsernameNotFoundException("User " + login + " was not found in the database"));
try {
persistentTokenRepository.saveAndFlush(token);
addCookie(token, request, response);
} catch (DataAccessException e) {
log.error("Failed to save persistent token ", e);
}
}

/**
* When logout occurs, only invalidate the current token, and not all user sessions.
* <p/>
* The standard Spring Security implementations are too basic: they invalidate all tokens for the
* current user, so when he logs out from one browser, all his other sessions are destroyed.
*/
@Override
@Transactional
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String rememberMeCookie = extractRememberMeCookie(request);
if (rememberMeCookie != null && rememberMeCookie.length() != 0) {
try {
String[] cookieTokens = decodeCookie(rememberMeCookie);
PersistentToken token = getPersistentToken(cookieTokens);
persistentTokenRepository.delete(token);
} catch (InvalidCookieException ice) {
log.info("Invalid cookie, no persistent token could be deleted");
} catch (RememberMeAuthenticationException rmae) {
log.debug("No persistent token found, so no token could be deleted");
}
}
super.logout(request, response, authentication);
}

/**
* Validate the token and return it.
*/
private PersistentToken getPersistentToken(String[] cookieTokens) {
if (cookieTokens.length != 2) {
throw new InvalidCookieException("Cookie token did not contain " + 2 +
" tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
}
String presentedSeries = cookieTokens[0];
String presentedToken = cookieTokens[1];
PersistentToken token = persistentTokenRepository.findOne(presentedSeries);

if (token == null) {
// No series match, so we can't authenticate using this cookie
throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
}

// We have a match for this user/series combination
log.info("presentedToken={} / tokenValue={}", presentedToken, token.getTokenValue());
if (!presentedToken.equals(token.getTokenValue())) {
// Token doesn't match series value. Delete this session and throw an exception.
persistentTokenRepository.delete(token);
throw new CookieTheftException("Invalid remember-me token (Series/token) mismatch. Implies previous " +
"cookie theft attack.");
}

if (token.getTokenDate().plusDays(TOKEN_VALIDITY_DAYS).isBefore(LocalDate.now())) {
persistentTokenRepository.delete(token);
throw new RememberMeAuthenticationException("Remember-me login has expired");
}
return token;
}

private String generateSeriesData() {
byte[] newSeries = new byte[DEFAULT_SERIES_LENGTH];
random.nextBytes(newSeries);
return new String(Base64.encode(newSeries));
}

private String generateTokenData() {
byte[] newToken = new byte[DEFAULT_TOKEN_LENGTH];
random.nextBytes(newToken);
return new String(Base64.encode(newToken));
}

private void addCookie(PersistentToken token, HttpServletRequest request, HttpServletResponse response) {
setCookie(
new String[]{token.getSeries(), token.getTokenValue()},
TOKEN_VALIDITY_SECONDS, request, response);
}

并且这样定义了一个安全配置类:

@Configuration
public class OAuth2ServerConfiguration {

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;

@Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

@Inject
private RememberMeServices rememberMeServices;

@Inject
private Environment env;

@Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
.rememberMeParameter("remember-me")
.key(env.getProperty("jhipster.security.rememberme.key"))
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.deleteCookies("JSESSIONID", "CSRF-TOKEN")
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers()
.antMatchers("/oauth/token")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/logs/**").hasAnyAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/api/**").authenticated()
.antMatchers("/metrics/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/health/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/dump/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/shutdown/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/beans/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/configprops/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/info/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/autoconfig/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/env/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/liquibase/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/protected/**").authenticated();
}
}

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Inject
private DataSource dataSource;

@Inject
private JHipsterProperties jHipsterProperties;

@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}

@Inject
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {

endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(jHipsterProperties.getSecurity().getAuthentication().getOauth().getClientid())
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
.secret(jHipsterProperties.getSecurity().getAuthentication().getOauth().getSecret())
.accessTokenValiditySeconds(jHipsterProperties.getSecurity().getAuthentication().getOauth().getTokenValidityInSeconds());
}
}

谢谢。

最佳答案

在 spring security oauth 中,由于 RememberMeAuthenticationFilter 未关联到登录 url (/oauth/token),记住我服务无法工作,即使在使用 rememberMe 配置器之后也是如此。

为了能够具有记住我的功能,必须使用刷新 token 来不断更新访问 token ,然后才能被记住。

您可以阅读这两篇文章以了解如何做到这一点。 http://www.baeldung.com/rest-api-spring-oauth2-angularjs http://www.baeldung.com/spring-security-oauth2-remember-me

关于java - Spring Security - 记住我自定义服务 onLoginSuccess 未使用 oauth2 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46084050/

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