Spring Security 流程

首先建立4個類ide

流程大體以下:this

一、容器啓動 加載系統資源與權限列表(HashMap) MyInvocationSecurityMetadataSourceService中的loadResourceDefineurl

@Service
public class MyInvocationSecurityMetadataSourceService  implements
        FilterInvocationSecurityMetadataSource {

    @Autowired
    private PermissionDao permissionDao;

    private HashMap<String, Collection<ConfigAttribute>> map =null;

    /**
     * 加載全部資源與權限的關係
     */
    public void loadResourceDefine(){
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<Permission> permissions = permissionDao.findAll();
        for(Permission permission : permissions) {
            array = new ArrayList<>();
            //角色名稱
            cfg = new SecurityConfig(permission.getName());
            array.add(cfg);
            map.put(permission.getUrl(), array);
        }


    }

    /**
     *返回請求資源所須要的權限
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if(map ==null) loadResourceDefine();
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        AntPathRequestMatcher matcher;
        String resUrl;
        for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
            resUrl = iter.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if(matcher.matches(request)) {
                return map.get(resUrl);
            }
        }
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
View Code

 

二、用戶發出請求spa

 

三、過濾器攔截 MyFilterSecurityInterceptor中的doFilter()code

@Service
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    /**
     * 過濾請求 調用FilterInvocationSecurityMetadataSource 資源和 MyAccessDecisionManager進行驗證
     */

    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        /**
         * FilterInvocation 把doFilter傳進來的request、response、chain對象保存起來
         */
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }
    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        //fi裏面有一個被攔截的url
        //裏面調用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的全部權限 HashMap中
        //再調用MyAccessDecisionManager的decide方法來校驗用戶的權限是否足夠
        //object爲FilterInvocation對象
        //
        //一、獲取請求資源的權限
        //執行Collection<ConfigAttribute> attributes=securityMetadataSource.getAttributes(fi);
        //二、是否擁有權限
        //執行 this.accessDecisionManager.decide(authenticated,fi,attributes);
        InterceptorStatusToken token = super.beforeInvocation(fi);
        /**
         * InterceptorStatusToken token = super.beforeInvocation(fi);會調用MyAccessDecisionManager中decide方法
         * 和MyInvocationSecurityMetadataSource中getAttributes方法
         */
        try {
            //執行下一個攔截器
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }


    @Override
    public void destroy() {

    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;

    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }
}
View Code

 

四、取得請求資源所需權限MyInvocationSecurityMetadataSourceService中getAttributes()對象

五、匹配用戶的權限和請求所須要的權限MyAccessDecisionManager中decide()blog

@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
    /**
     * @param authentication 用戶具備的角色權限,認證的入口
     * @param object 當前正在請求的受保護的對象
     * @param configAttributes 受保護對象的配置屬性—所具備的權限
     * @throws AccessDeniedException
     * @throws InsufficientAuthenticationException
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        //若是訪問資源不須要任何權限則直接經過
        if(null== configAttributes || configAttributes.size() <=0) {
            return;
        }
        ConfigAttribute c;
        String needRole;
        //遍歷configAttributes看用戶是否有訪問資源的權限
        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
            c = iter.next();
            needRole = c.getAttribute();
            for(GrantedAuthority ga : authentication.getAuthorities()) {
                //ga 用戶所被賦予的權限,needRole 訪問相應資源應具備的權限
                if(needRole.trim().equals(ga.getAuthority())) {
                    return;
                }
            }
        }
        // 若是訪問被拒絕,實現將拋出一個AccessDeniedException異常。
        throw new AccessDeniedException("no right");
    }



    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
View Code

 

六、登陸token

@Service
public class CustomUserService implements UserDetailsService { //自定義UserDetailsService 接口

    @Autowired
    UserDao userDao;
    @Autowired
    PermissionDao permissionDao;

    /**
     *點擊登陸跳轉 保存用戶權限
     *
     */
    public UserDetails loadUserByUsername(String username) {
        SysUser user = userDao.findByUserName(username);
        if (user != null) {
            List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());
            List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
            for (Permission permission : permissions) {
                if (permission != null && permission.getName()!=null) {
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
                grantedAuthorities.add(grantedAuthority);
                }
            }
            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
        } else {
            throw new UsernameNotFoundException("admin: " + username + " do not exist!");
        }
    }

}
View Code

七、驗證並受權接口

相關文章
相關標籤/搜索