Solved it and for me it works perfect and looks beautiful.
Unfortunetly there is no real short answer for it, personally I spent a lot of time on the internet and then kinda just build it up by myself but maybe it helps someone:
- used Spring Security combined with JWT --> use UserDetails by Spring, implement service(only loadByUsername is really necessary to implement in this class so that at log in spring security looks for the user in the database) and dto of it and set the right configuration telling Spring you want to use JWT, BCRYPT (see in Configuration Class below)
- used BCRYPT (salt and hash with only calling a method and Autowire BCRYPT) (see UserDetailsService)
- set password as string instance, every java string gets by default mapped to VARCHAR(255) in database mySQL
A lot of code for JWT for example you just have to copy. But I will show my UserDetailsService which is more a individual thing, for managing users, and also a part of the configuration which tells spring how to handle authorities and authorization including JWT and all that.
Configuration
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Value("${jwt.get.token.uri}")
private String authenticationPath;
/**
* Configure AuthenticationManager so that it knows from where to load user for
* matching credentials. Use BCryptPasswordEncoder.
*
* @param auth which creates authentication manager
* @throws Exception if authentication manager has problems
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* Configure who has access to which URLs. Organize authorities and their needed
* Authorization.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// no need of CSRF
http.csrf().disable()
// authenticate particular requests
.authorizeRequests().antMatchers("/adm/*").hasAuthority("ADMIN")
.antMatchers("/store/{username}/*").hasAuthority("STORE").and()
// make sure we use stateless session; session won't be used to
// store user's state.
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
/**
* Configure which URLs can be ignored by spring web security. Thus there is no
* authentication.
*/
@Override
public void configure(WebSecurity webSecurity) throws Exception {
// no authentification needed for specific URLs (login request,...)
webSecurity.ignoring().antMatchers(HttpMethod.POST, authenticationPath)
.antMatchers(HttpMethod.OPTIONS, "/**");
}
}
UserDetailsServcie
@Service
public class JwtUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userrepo;
@Autowired
private RetailStoreRepository storerepo;
@Autowired
private PasswordEncoder bcryptEncoder;
// Aggregated root
public List<User> findAllUser() {
return userrepo.findAll();
}
// Single Item
/**
* Add new user (ADMIN or STORE).
*
* @param account information about new user
* @return new user
*/
public AccountDto addUser(AccountDto account) {
String username = account.getUser().getUsername();
// encode password (hashing)
String code = bcryptEncoder.encode(account.getUser().getPassword()).toString();
Role role = account.getUser().getRole();
// create new user
User user = new User(username, code, role);
// add new user to database
userrepo.save(user);
// check authorization and add store if needed
if (account.getUser().getRole().equals(Role.STORE) && account.getStore() != null) {
storerepo.save(account.getStore());
}
return account;
}
/**
* Delete user.
*
* @param userId id of user who is deleted
*/
public void deleteUser(Long userId) {
// check if user exists
if (userrepo.existsById(userId)) {
userrepo.deleteById(userId);
// also delete corresponding retail store if it is no admin
User user = userrepo.findById(userId).get();
if (user.getRole().equals(Role.STORE)) {
RetailStore trashStore = storerepo.findByUser_userId(userId);
storerepo.delete(trashStore);
}
} else {
throw new UserNotFoundException(userId);
}
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userrepo.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new JwtUserDetailsDto(user.getUserId(), user.getUsername(), user.getPassword(),
user.getRole().toString());
}
}