I have a simple (still a demo program at this point) Spring program (Spring Rest and Security) that works in a plain way. Through JpaRepository I can GET all (/option handled by findAll()), GET one (/option/1 handled by findOne(Long id)), PUT and POST.
My business model says that a logged-in user should see only the records they have rights to. So a findAll() should return maybe three records, a findOne(id) should return one or zero.
I believe I must tie these to the Principal object in an annotation. I've tried a variety of schemes but haven't yet figured what Spring wants of me. For the findAll() I've tried this:
@Override
@Query("from Option o where o.id = 11")
public List<Option> findAll();
However, findAll() still returns many records.
Then I tried to tie my query to the Principal:
@Override
@Query("from Option o where o.id = ?#{ principal.id}")
public List<Option> findAll();
(I've also tried ?#{#principal.id} )
This fails in interesting ways.
Here is how I expose a UserDetailsService:
@Service
public class JwtUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Here is how I configure the principal in the pom.xml:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
<!-- <version>4.2.1.RELEASE</version> -->
</dependency>
and in Java:
@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder());
}
My questions are:
Thanks, Jerome.
Why doesn't the @Query("from Option o where o.id = 11") return only one record?
Because this is not a valid JPQL-query. Your hardcoded test-query must be @Query("SELECT o FROM Option o WHERE o.id = 11")
How can I tell the attributes of "principal", so I can tell if its ID is what I think it is?
Your must enable the Spring Security SpEL functions for queries.
@Configuration
@EnableJpaRepositories
class SecurityConfiguration {
@Bean
EvaluationContextExtension securityExtension() {
return new SecurityEvaluationContextExtension();
}
}
It`s explained here.
Now ?#{principal.id}
will work, if you have a custom UserDetails
-Implementation with an id
-field. For example:
import org.springframework.security.core.userdetails.User;
public class HapaUserDetails extends User { //User implements UserDetails
private final long id;
//constructor and getters
}