The basic framework is created already.
and create new class of it:
DaoUserDetailServices
1. JWT Auth
2. Hello Rest API.
now, it will be good time to switch to database based user authorization.
we use customized userDetailService instead of default in memeory user services.
Replace InMemeory UserDetailService as DaoUserDetallService
@Autowiredprivate UserDetailsService userDetailService; @Autowiredpublic void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailService); }
and create new class of it:
@Primary@Servicepublic class DaoUserDetailServices implements UserDetailsService { @Autowired private PasswordEncoder bCryptPasswordEncoder; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { if(name.equals("admin")) { return new UserPrincipal(name, bCryptPasswordEncoder.encode("password"), "ADMIN"); } else if(name.equals("user")) { return new UserPrincipal(name, bCryptPasswordEncoder.encode("password"), "USER"); } else return null; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
public class UserPrincipal implements UserDetails { private final String name; private final String password; private final String admin; public UserPrincipal(String name, String password, String admin) { this.name = name; this.password = password; this.admin = admin; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return this.password; } @Override public String getUsername() { return this.name; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
we don't touch any hibernate yet, all we did is just hardcode the in memeory logic to here and have all test cases passed(very important, one small successful step will help build big scope more efficiently instead of having all-in-one and then debug in mess.)
Hook up with database.
POM.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope></dependency>
There is hibernate bug with postgresql due the critical key word "user" in database
Wrong:
@Entity@Tablepublic class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(nullable = false, unique = true) private String name; @Column(nullable = false, columnDefinition="default ''") private String password; ... }
Correct:
@Entity@Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(nullable = false) private String name; @Column private String password;
...
}
UserRepository
public interface UserRepository extends JpaRepository<User, Long> { List<User> findByName(String name);}
DaoUserDetailServices
@Primary@Servicepublic class DaoUserDetailServices implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { var user = userRepository.findByName(name).stream().findFirst().orElse(null); if(user == null) { return null; } return new UserPrincipal(user.getName(), user.getPassword(), user.getRole()); } }
Setup different database for unit test.
copy main application.properties and data.sql to test folder, and change the database name as demospring.datasource.url=jdbc:postgresql://localhost:5432/demo
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.datasource.initialization-mode=always
Comments
Post a Comment