zoukankan      html  css  js  c++  java
  • Spring Security 流程

    首先创建4个类

    流程大致如下:

    1、容器启动 加载系统资源与权限列表(HashMap) MyInvocationSecurityMetadataSourceService中的loadResourceDefine

    @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

    2、用户发出请求

    3、过滤器拦截 MyFilterSecurityInterceptor中的doFilter()

    @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对象
            //
            //1、获取请求资源的权限
            //执行Collection<ConfigAttribute> attributes=securityMetadataSource.getAttributes(fi);
            //2、是否拥有权限
            //执行 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

    4、取得请求资源所需权限MyInvocationSecurityMetadataSourceService中getAttributes()

    5、匹配用户的权限和请求所需要的权限MyAccessDecisionManager中decide()

    @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

    6、登录

    @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

    7、验证并授权

  • 相关阅读:
    cookie的使用
    给定一个数组和一个目标值,找出和为目标值的整数,并返回他们的下标
    String详解
    阳哥讲面试题(四)生产调优
    springboot项目调优(针对特性的服务启动,定制化诉求)
    intern() 方法
    阳哥讲面试题(四)OOM,GC算法,垃圾收集器
    阳哥讲面试题(三)JVM,GC
    阳哥讲面试题(二)队列,线程池
    Semaphore用法
  • 原文地址:https://www.cnblogs.com/whtgjy/p/9556112.html
Copyright © 2011-2022 走看看