方案一:扩展access()的SpEL表达式html
.anyRequest().access("@authService.canAcess(request,authentication)")spring
方案二:自定义AccessDecisionManager数据库
(1)自定义SecurityMetadataSource,实现从数据库加载ConfigAttributesession
(2)自定义accessDecisionManager,进行权限校验ide
(3)使用withObjectPostProcessor,自定义SecurityMetadataSource和accessDecisionManagerfetch
方案三:自定义Filterthis
spring security原本就是由不少的Filter构成的,那么咱们能够自定义Filter而后添加到fiterChain中url
(1)须要提供认证数据规则数据源数据:经过实现接口FilterInvocationSecurityMetadataSource来进行实现。.net
(2)自定义accessDecisionManager:进行权限校验code
(3)自定义一个拦截器而后把它添加到spring security的fiterChain
这里使用方案一。
1、建立实体类Permission
@Entity public class Permission { @Id @GeneratedValue private long id; // 主键 private String name; // 权限名称 private String description; // 权限名称 /** * 注意:Permission表的ulr通配符为两颗星,好比/user下的全部url,应该写成/user/** */ private String url; // 受权链接 private Long pid; // 父节点 // 角色 - 权限是多对多的关系 @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; }
2、创建RoleRepository
public interface RoleRepository extends JpaRepository<Role,Long> { }
3、建立service类
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 /** * 从数据库中获取全部权限信息,而后进行遍历,存储到permissionMap集合中 */ 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; } }
4、初始化数据
@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("管理员"); roleRepository.save(adminRole); roles.add(adminRole); Role userRole = new Role(); userRole.setName("normal"); userRole.setDescprtion("普通用户"); roleRepository.save(userRole); roles.add(userRole); Permission userPermission = new Permission(); userPermission.setName("普通用户的url"); userPermission.setDescription("容许普通用户访问"); userPermission.setUrl("/hello/helloUser"); userPermission.setRoles(roles); permissionRepository.save(userPermission); Permission adminPermission = new Permission(); adminPermission.setName("管理员的url"); adminPermission.setDescription("容许管理员访问"); 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、基于url动态获取权限并匹配
@Service public class AuthService { @Autowired private PermissionService permissionService; public boolean canAcess(HttpServletRequest request, Authentication authentication) { boolean b = false; String url = request.getRequestURI(); /** * 一、未登陆的状况下,须要坐一个判断或者是拦截。 */Object principal = authentication.getPrincipal(); if(principal == null || "anonymousUser".equals(principal)) { return b; } /** * 二、匿名的角色ROLE_ANONYMOUS */ if(authentication instanceof AnonymousAuthenticationToken) { // 匿名角色 // check // return } /** * 三、经过requst对象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; } /** * 四、将获取到的权限信息和当前的登录帐号的权限信息进行对比 */ 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、使用.anyRequest().access()
@Override protected void configure (HttpSecurity http) throws Exception{ http.formLogin().loginPage("/login") .and() .authorizeRequests() .antMatchers("/login").permitAll() //容许全部人能够访问登录页面 .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();//全部的请求须要在登录以后才能访问 }
遇到问题: 一、登录成功后老是现实无权访问,这里先将首页设为因此可见。
.antMatchers("/","/index").permitAll()
二、登录成功后老是访问/favicon.ico,致使权限没法匹配成功,解决办法是加一个/favicon.ico图片,再在使用的页面调用。还有更好的办法。 https://www.jianshu.com/p/b56e524ba2e8 https://blog.csdn.net/sdjadycsdn/article/details/82621234