基於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

相關文章
相關標籤/搜索