Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA + MySql + Implement encrypted password

as I am building a Login for a Website I would like to store a auto generated password in MySQL in a safe way, thus encrypt it in some way. But I am not sure how to combine the auto generation with encrypting the password.

I looked at a lot of questions but none really helped me or answered my question considering that it should be autogenerated. Also I would like to solve it in an elegant way without hardcoding and stuff if possible. I would be really happy if someone could help me as I am a beginner, thanks in advance!

Question:

How do I auto generate a secure encrypted passwords, what datatype should I use in Java (currently String) and then to what database type is it mapped?

How do I make sure I can decrypt the password of the database to check if it matches when someone logs in?

User Entity:

@Entity
public class User {

    @Id
    @GeneratedValue
    private Integer user_id;
    
    @Column(unique = true)
    private String username;
    
    private String password;
    
    @Enumerated(EnumType.STRING)
    private Role role;
    
    //non-Owning (address) side of the OneToOne relationship
    @OneToOne(mappedBy = "user")
    private RetailStore retailStore;

    /**
     * Constructor
     */
    protected User() {
        
    }
    
    /**
     * Constructor
     * @param username
     * @param role
     */
    public User(String username, String password, Role role) {
        super();
        this.username = username;
        this.password = password;
        this.role = role;
    }

User Repository:

@Repository
@Transactional
//necessary to be in an transaction to change something in database, 
//instead of doing this for every method itself it is declared by 
//the annotation @Transactional
public interface UserRepository extends JpaRepository<User, Long>{
    
}
like image 885
nin-prog Avatar asked Dec 31 '25 03:12

nin-prog


1 Answers

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());
  }

}
like image 136
nin-prog Avatar answered Jan 01 '26 18:01

nin-prog