1. spring security is for permission authentication.
2. Database based authentication is used in all projects.
First, we create a permission related table.
General authority controls include
user → role → data_privilege
user →data_privilege
Users control through role. Data permission is bound with role. The advantage is that users can control their permission in batches.
It is flexible for a single user to make a single setting.
-- User table CREATE TABLE t_user( id int , username varchar(32), password varchar(255), enabled tinyint(1), locked tinyint(1) ) --- Role table create table t_role( id int, nameEN varchar(32), nameZH varchar(50) ) ---User role table create table t_user_role( id int, uid int, rid int ) ---User roles url create table t_role_url( id int, rid int, urlId int ) ---User menu table create table t_menu( id int, url varchar(255), desc varchar(50), actived TINYINT(1) ) ---User data permission table create table t_data_privileg( id int , idType varchar(32), authIds int, privId int, privType int, isDel tinyint(1), create_date TIMESTAMP, expire_date TIMESTAMP )
3. Need to implement loadUserByUsername method of UserDetailService
/** * */ package com.security.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.security.dao.UserMapper; import com.security.entity.User; /** * @author fandong * */ @Service public class UserService implements UserDetailsService{ @Autowired public UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // TODO Auto-generated method stub System.out.println("start Call database to continue query....."); User user = userMapper.loadUserByUsername(username); if(user == null) { throw new UsernameNotFoundException("Account does not exist"); } user.setRoles(userMapper.getUserRolesByUid(user.getId())); System.out.println(user.toString()); return user; } }
4. Implement User UserDetail interface
/** * */ package com.security.entity; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; /** * @author fandong * */ public class User implements UserDetails{ @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + ", enabled=" + enabled + ", locked=" + locked + ", roles=" + roles + "]"; } private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } private String username; private String password; private Boolean enabled; private Boolean locked; private List<Role> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO Auto-generated method stub List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>(); for(Role role: roles) { authorities.add(new SimpleGrantedAuthority(role.getNameEN())); } System.out.println("-----------Get permission list-------"); return authorities; } @Override public String getPassword() { // TODO Auto-generated method stub return password; } @Override public String getUsername() { // TODO Auto-generated method stub return username; } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return enabled; } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; } }
5. Implement UserMapper method
/** * */ package com.security.dao; import java.util.List; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.springframework.security.core.userdetails.UsernameNotFoundException; import com.security.entity.Role; import com.security.entity.User; /** * @author fandong * */ public interface UserMapper { @Select("select * from t_user where username=#{username}") User loadUserByUsername(@Param("username") String username) throws UsernameNotFoundException; @Select("select * from t_role r,t_user_role ur where r.id=ur.rid and ur.uid=#{id}") List<Role> getUserRolesByUid(@Param("id") Integer id); }
5. Show WebSecurityConfigurerAdapter
/** * */ package com.security.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.security.service.UserService; /** * @author fandong * */ @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder PasswordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Autowired UserService userService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // TODO Auto-generated method stub auth.userDetailsService(userService); } @Override protected void configure(HttpSecurity http) throws Exception { // TODO Auto-generated method stub System.out.println("Start executing......."); http.authorizeRequests().antMatchers("/admin/**").hasRole("admin") .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login").permitAll() .and() .csrf() .disable(); //super.configure(http); } }
Note that when roles are matched, the prefix "ROLE" is automatically added.
6. Test Controller
package com.security.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/admin/hello") public String admin() { return "hello,admin!"; } @RequestMapping("/hello") public String hello() { return "hello"; } }
7. For testing, the database storage ROLE name must be prefixed with "ROLE".