当我为网站建立登录时,我想以一种安全的方式将自动生成的密码存储在 MySQL 中,从而以某种方式对其进行加密。但我不确定如何将自动生成与加密密码结合起来。
我看了很多问题,但没有一个真正帮助我或回答我的问题,因为它应该是自动生成的。另外,如果可能的话,我想以一种优雅的方式解决它,而无需硬编码和其他东西。如果有人能帮助我,我会很高兴,因为我是初学者,在此先感谢!
问题:
我如何自动生成安全的加密密码,我应该在 Java 中使用什么数据类型(目前是字符串),然后它映射到什么数据库类型?
如何确保我可以解密数据库的密码以检查它是否在有人登录时匹配?
用户实体:
@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;
}
用户存储库:
@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>{
}
最佳答案
解决了它,对我来说它工作完美而且看起来很漂亮。
不幸的是,没有真正的简短答案,就我个人而言,我花了很多时间在互联网上,然后有点自己构建它,但也许它对某人有帮助:
- 使用 Spring Security 结合 JWT --> 通过 Spring 使用 UserDetails,实现服务(只有 loadByUsername 是真正需要在此类中实现的,以便在登录时 spring security 在数据库中查找用户)和它的 dto 和设置正确的配置,告诉 Spring 你想使用 JWT,BCRYPT(见下面的配置类)
- 使用 BCRYPT(仅调用方法和 Autowiring BCRYPT 的盐和散列)(参见 UserDetailsService)
- 将密码设置为字符串实例,每个 java 字符串默认映射到数据库 mySQL 中的 VARCHAR(255)
例如 JWT 的许多代码,您只需复制即可。但我将展示我的 UserDetailsService,它更像是一个单独的东西,用于管理用户,也是配置的一部分,它告诉 spring 如何处理权限和授权,包括 JWT 等等。
配置
@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());
}
}
关于java - JPA + MySql + 实现加密密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63217082/