基于url的动态权限

方案一:扩展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

相关文章
相关标签/搜索