Reputation: 37
I am currently in the process of developing a web application in Java using Spring Boot.
What I am using for the app:
Currently my database has a table for users and roles. Login, registration and sessions are working fine.
I have created an admin-only page on the site.
I am having issues with creating and using roles for users.
I'd like to have a role for every user in the DB and be able to use it on the site. The default role on registration would be "USER", and I would be able to manually change an user's role to "ADMIN" in the MySQL admin.
This is currently my User entity class:
@Entity
@Table(name = "user")
public class User extends Auditable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;
@Column(name = "email", nullable = false, unique = true)
@Email(message = "Please provide a valid e-mail")
@NotEmpty(message = "Please provide an e-mail")
private String email;
@Column(name = "password")
@Transient
private String password;
@Column(name = "first_name")
@NotEmpty(message = "Please provide your first name")
private String firstName;
@Column(name = "last_name")
@NotEmpty(message = "Please provide your last name")
private String lastName;
@Column(name = "enabled")
private boolean enabled;
@Column(name = "confirmation_token")
private String confirmationToken;
@OneToOne(mappedBy="user", cascade={CascadeType.ALL})
private Role role;
public User() {
}
public User(String firstName, String lastName, String email, String password, Role role) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.role = role;
}
/** Getters and setters */
}
This is my Role entity:
@Entity(name="role")
public class Role {
@Id
private Long id;
@OneToOne
private User user;
private Integer role;
/** Getters and setters */
}
Load by username in UserService:
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if (user == null){
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(), getAuthorities(user.getRole().getRole()));
}
But for some reason this is not working. It creates the "role" table in the DB, and it has two rows in it
id name
1 ROLE_USER
2 ADMIN
Question is, what do I need to do when I am saving the user to the DB in order to set a role for the user I am saving? Currently none of the user rows in my table have a role column. And how can I make it work so that when I have a rule in my securityconfig;
.hasRole("ADMIN")
It won't allow an user without that role to access? Currently when I try to access the page with that rule, it always returns the no access page I've configured.
Upvotes: 1
Views: 5031
Reputation: 786
Below is my code for implementing registration and assigning rolse to a registered user.
1) User.java (@Entity)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long user_id;
private String username;
private String password;
private boolean active;
private String email;
// user roles
@ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
@CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
@Enumerated(EnumType.STRING)
private Set<Role> roles;
// Constructors
private User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
// if user is admin
public boolean isAdmin() {
return roles.contains(Role.ADMIN);
}
// Below you can generate getters & setters & toString method.
// Getter and setter for user roles
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
Role.java (enum type)
public enum Role {
USER,
ADMIN;
}
UserController.java (@Controller)
@Controller
public class UserController{
//login page
@GetMapping("/signin")
public String loginPage() {
return "frontend/login";
}
// registration page
@GetMapping("/signup")
public String signUpPage() {
return "frontend/registration";
}
// User Registration
@PostMapping("/signup")
public String addUser(User user, Map<String, Object> model) {
User userFromDB = userRepository.findByUsername(user.getUsername());
if(userFromDB !=null ) {
model.put("alreadyexists", "Username already exists!");
return "frontend/registration";
}
// Set user apssword (also you can implement BCrypt)
user.setPassword(user.getPassword());
// set user activa
user.setActive(true);
// assign Rolr USER to newly registered user
user.setRoles(Collections.singleton(Role.USER));
userRepository.save(user);
return "redirect:/profile";
}
}
WebsecurityConfig.java (Spring Security)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/","/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/signin").defaultSuccessUrl("/profile")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/signout")).logoutSuccessUrl("/signin?bye")
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("SELECT username, password, active FROM users WHERE username=?")
.authoritiesByUsernameQuery("SELECT u.username, ur.roles FROM users u INNER JOIN user_role ur ON u.user_id = ur.user_id WHERE u.username=?");
}
}
Upvotes: 1