Solution 1: Extend the SpEL expression of access()
.anyRequest().access("@authService.canAcess(request,authentication)")
Solution 2: Customize Access Decision Manager
(1) Customize Security Metadata Source to load ConfigAttribute from database
(2) Customize access decision manager to verify permissions
(3) Customize Security Metadata Source and AccessDecision Manager using withObjectPostProcessor
Solution 3: Custom Filter
spring security is made up of a lot of filters, so we can customize filters and add them to fiterChain.
(1) Authentication data rules data source data need to be provided: through the implementation of the interface FilterInvocation Security Metadata Source to achieve.
(2) Custom Access Decision Manager: Perform permission validation
(3) Customize an interceptor and add it to fiterChain of spring security
Here we use scheme 1.
I. Creating the Entity Class Permission
@Entity public class Permission { @Id @GeneratedValue private long id; // Primary key private String name; // Permission name private String description; // Permission name /** * Note: The ulr wildcard of the Permission table is two stars, for example, all URLs under / user should be written as / user/** */ private String url; // Authorized connection private Long pid; // Parent node // Role-authority is a many-to-many relationship @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "RolePermission",joinColumns = {@JoinColumn(name="permission_id")},inverseJoinColumns = {@JoinColumn(name="role_id")}) private List<Role> roles; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; }
Establishment of Role Repository
public interface RoleRepository extends JpaRepository<Role,Long> { }
3. Creating service classes
public interface PermissionService { Map<String, Collection<ConfigAttribute>> getPermissionMap (); } @Service public class PermissionServiceImpl implements PermissionService { @Autowired private PermissionRepository permissionRepository; private Map<String, Collection<ConfigAttribute>> permissionMap = null; @PostConstruct /** * Get all the privilege information from the database, then traverse it and store it in the permissionMap collection */ public void initPermissions() { permissionMap = new HashMap<>(); List<Permission> permissions = permissionRepository.findAll(); for (Permission p : permissions) { Collection<ConfigAttribute> collection = new ArrayList<ConfigAttribute>(); for (Role role : p.getRoles()) { ConfigAttribute configAttribute = new SecurityConfig("ROLE_"+role.getName()); collection.add(configAttribute); } permissionMap.put(p.getUrl(),collection); } System.out.println(permissionMap); } @Override public Map<String,Collection<ConfigAttribute>> getPermissionMap (){ if(permissionMap == null || permissionMap.size() == 0){ initPermissions(); } return permissionMap; } }
IV. Initialization data
@Service public class DataInit { @Autowired private UserInfoRepository userInfoRepository; @Autowired private PasswordEncoder passwordEncoder; @Autowired private RoleRepository roleRepository; @Autowired private PermissionRepository permissionRepository; @PostConstruct public void dataInit(){ // role List<Role> roles = new ArrayList<>(); Role adminRole = new Role(); adminRole.setName("admin"); adminRole.setDescprtion("Administrators"); roleRepository.save(adminRole); roles.add(adminRole); Role userRole = new Role(); userRole.setName("normal"); userRole.setDescprtion("Ordinary users"); roleRepository.save(userRole); roles.add(userRole); Permission userPermission = new Permission(); userPermission.setName("Ordinary user's url"); userPermission.setDescription("Allow ordinary user access"); userPermission.setUrl("/hello/helloUser"); userPermission.setRoles(roles); permissionRepository.save(userPermission); Permission adminPermission = new Permission(); adminPermission.setName("Administrator url"); adminPermission.setDescription("Allow Administrator Access"); adminPermission.setUrl("/hello/helloAdmin"); roles = new ArrayList<>(); roles.add(adminRole); adminPermission.setRoles(roles); permissionRepository.save(adminPermission); // admin UserInfo admin = new UserInfo(); admin.setUsername("admin"); admin.setPassword(passwordEncoder.encode("123")); admin.setRoles(roles); userInfoRepository.save(admin); // user roles = new ArrayList<>(); roles.add(userRole); UserInfo user = new UserInfo(); user.setUsername("user"); user.setPassword(passwordEncoder.encode("123")); user.setRoles(roles); userInfoRepository.save(user); } }
5. Dynamic access and matching based on url
@Service public class AuthService { @Autowired private PermissionService permissionService; public boolean canAcess(HttpServletRequest request, Authentication authentication) { boolean b = false; String url = request.getRequestURI(); /** * 1,If you are not logged in, you need to make a judgment or intercept. */Object principal = authentication.getPrincipal(); if(principal == null || "anonymousUser".equals(principal)) { return b; } /** * 2,Anonymous role ROLE_ANONYMOUS */ if(authentication instanceof AnonymousAuthenticationToken) { // Anonymous role // check // return } /** * 3,Access permission information through requst object url */ Map<String, Collection<ConfigAttribute>> map = permissionService.getPermissionMap(); Collection<ConfigAttribute> configAttributes = null; for (Iterator<String> it = map.keySet().iterator();it.hasNext();) { String curUrl = it.next(); AntPathRequestMatcher matcher = new AntPathRequestMatcher(curUrl); if (matcher.matches((request))) { configAttributes = map.get(curUrl); break; } } if(configAttributes == null || configAttributes.size() == 0) { return b; } /** * 4,Compare the access information obtained with the access information of the current login account. */ for(Iterator<ConfigAttribute> it = configAttributes.iterator();it.hasNext();){ ConfigAttribute cfa = it.next(); String role = cfa.getAttribute(); for(GrantedAuthority authority : authentication.getAuthorities()){ if(role.equals(authority.getAuthority())){ b = true; break; } } } return b; } }
6. Use. anyRequest().access()
@Override protected void configure (HttpSecurity http) throws Exception{ http.formLogin().loginPage("/login") .and() .authorizeRequests() .antMatchers("/login").permitAll() //Allow everyone access to the landing page .antMatchers("/","/index").permitAll() .antMatchers("/test/**","/test1/**","/favicon.ico").permitAll() .antMatchers("/res/**/*.{js,html}").permitAll() .anyRequest().access("@authService.canAcess(request,authentication)") .and().sessionManagement().maximumSessions(1); //anyRequest().authenticated(); // All requests need to be accessed after login }
Problems encountered: 1. After successful landing, there is always no real right to visit. Here, first set the home page as visible.
.antMatchers("/","/index").permitAll()
2. After successful login, always visit / favicon.ico, which leads to the mismatch of permissions. The solution is to add a / favicon.ico image and call it on the page in use. There are better ways. https://www.jianshu.com/p/b56e524ba2e8 https://blog.csdn.net/sdjadycsdn/article/details/82621234