Ich erstelle Rest API mit Spring Boot v1.3.3. API wird von Spring Security gesichert. Ich habe den benutzerdefinierten Benutzerdetaildienst implementiert, um den benutzerdefinierten Prinzipal im Authentifizierungskontext zu haben.Authentifizierung Principal ist leer, während Spring Session Redis
Ich musste Sitzungen der API mit anderen Spring-App teilen, also wählte ich Spring Session mit Redis-Server in meiner App mit diesem Tutorial docs.spring.io/spring-session/docs/current/reference/html5/ guides/security.html. Unglücklicherweise hat es dazu geführt, dass der Authentication Principal nicht mehr funktionierte. Wenn ich versuche, den aktuellen Principal entweder durch die Annotation @AuthenticationPrincipal CustomUserDetails user
oder durch SecurityContextHolder.getContext().getAuthentication().getPrincipal()
zu erhalten, werden meine benutzerdefinierten Benutzerdetails zurückgegeben, aber mit Id = 0
und allen Feldern null
(screen from debugging). Ich kann nicht einmal den Benutzernamen von SecurityContextHolder.getContext().getAuthentication().getName()
bekommen.
Nachdem ich Redis Code und Maven Abhängigkeit kommentiert funktioniert es (see debug screen). Wie funktioniert es mit Spring Session und Redis Server?
Hier ist ein Code aus der App: für
@Configuration
@EnableRedisHttpSession
public class AppConfig {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
@Bean
public ShaPasswordEncoder shaEncoder() {
return new ShaPasswordEncoder(256);
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean(name = "messageSource")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
resourceBundleMessageSource.setBasename("messages/messages");
return resourceBundleMessageSource;
}
@Bean
public Validator basicValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
public AppConfig() {
DateTimeZone.setDefault(DateTimeZone.UTC);
}
}
Initializer (gebraucht:
Einige Beispielverfahren Haupt
@RequestMapping(value = "/status", method = RequestMethod.GET)
public StatusData status(@AuthenticationPrincipal CustomUserDetails user) {
User user2 = (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (user != null) {
String name = user.getUsername();
return new StatusData(name);
} else return new StatusData(null);
}
Anwendung und Redis Config überprüfen Redis Session)
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
SecurityInitializer (für Redis Sitzung)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(WebSecurityConfig.class, AppConfig.class);
}
}
WebSecurityConfig (Spring Security Config)
@Configuration
@EnableWebSecurity
//@EnableWebMvcSecurity
@ComponentScan(basePackageClasses = {UserRepository.class, CustomUserDetailsService.class})
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsService customUserDetailsService;
@Autowired
private HttpAuthenticationEntryPoint httpAuthenticationEntryPoint;
@Autowired
private AuthSuccessHandler authSuccessHandler;
@Autowired
private AuthFailureHandler authFailureHandler;
@Autowired
private HttpLogoutSuccessHandler logoutSuccessHandler;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
/**
* Persistent token repository stored in database. Used for remember me feature.
*/
@Bean
public PersistentTokenRepository tokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
/**
* Enable always remember feature.
*/
@Bean
public AbstractRememberMeServices rememberMeServices() {
CustomTokenPersistentRememberMeServices rememberMeServices = new CustomTokenPersistentRememberMeServices("xxx", customUserDetailsService, tokenRepository());
rememberMeServices.setAlwaysRemember(true);
rememberMeServices.setTokenValiditySeconds(1209600);
return rememberMeServices;
}
/**
* Configure spring security to use in REST API.
* Set handlers to immediately return HTTP status codes.
* Enable remember me tokens.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(httpAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/cookie", "/register", "/redirect/**", "/track/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(authSuccessHandler)
.failureHandler(authFailureHandler)
.and()
.logout()
.permitAll().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler)
.and()
.rememberMe().rememberMeServices(rememberMeServices())
.and()
.headers()
.addHeaderWriter(new HeaderWriter() {
/**
* Header to allow access from javascript AJAX in chrome extension.
*/
@Override
public void writeHeaders(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String corsUrl = "https://mail.google.com";
if (httpServletRequest.getHeader("Origin") != null && httpServletRequest.getHeader("Origin").equals(corsUrl)) {
httpServletResponse.setHeader("Access-Control-Allow-Origin", "https://mail.google.com");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("Access-Control-Expose-Headers", "Location");
}
}
});
}
/**
* Set custom user details service to allow for store custom user details and set password encoder to BCrypt.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
}
Maven Abhängigkeiten
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>models</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.3.Final</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.core</artifactId>
<version>3.1.0.CR1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
</dependency>
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.ganyo</groupId>
<artifactId>gcm-server</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.4.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Ich habe auch eine benutzerdefinierte UserDetails, und ich habe es geändert, um Serializable zu implementieren (öffentliche Klasse MyUserDetails erweitert org.springframework.security.core.userdetails.User implementiert Serializable).Ich verwende Spring Session mit JDBC-Backend, aber die Spalte Prinzipalname ist NULL. Seltsam. – yglodt
Ich stimme @yglodt zu, das ist vielleicht nicht die gute Antwort. Wenn Sie die 'org.springframework.security.core.userdetails.UserDetails' Klasse überprüfen, wird die' java.io.Serializable' Schnittstelle bereits erweitert – BigDong