`

学习acegi-security (转载)

阅读更多
学习acegi-security
这几天对acegi研究了一下,现对这几天的研究做个总结。

网上资料对于acegi在web上的应用非常多,所以特意不从web入手,而从一般的java方法入手。

acegi的基本原理就是利用拦截器,对请求进行拦截,在拦截前和拦截后做些安全验证,以达到安全目的。所谓安全,一般包括两个部分,一为认证(authentication),二为授权(authorization)。

1,拦截器体系
acegi中拦截器为分为三类:
(1)filter拦截器(FilterSecurityInterceptor),主要对web应用进行拦截,即利用servlet的filter进行拦截。
(2)method拦截器,分为spring的method拦截器(MethodSecurityInterceptor)和aspectj的method拦截器(AspectJSecurityInterceptor)。


代码
public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware,  
    MessageSourceAware {  
    private AccessDecisionManager accessDecisionManager;  
    private AfterInvocationManager afterInvocationManager;  
    private ApplicationEventPublisher eventPublisher;  
    private AuthenticationManager authenticationManager;  
    protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();  
    private RunAsManager runAsManager = new NullRunAsManager();  
    private boolean alwaysReauthenticate = false;  
    private boolean rejectPublicInvocations = false;  
    private boolean validateConfigAttributes = true;  
    .........  
 
    protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) {  
       ............  
    SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());  
    ............  
       if (afterInvocationManager != null) {  
            returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),token.getAttr(), returnedObject);  
        }  
       ............  
    }  
 
    protected InterceptorStatusToken beforeInvocation(Object object) {          
      ............  
         authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext().getAuthentication());  
      ............  
         this.accessDecisionManager.decide(authenticated, object, attr);  
         ............  
         Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);  
         if (runAs == null) {  
        ............  
              return new InterceptorStatusToken(authenticated, false, attr, object);   
         } else {  
        ............  
              SecurityContextHolder.getContext().setAuthentication(runAs);  
              return new InterceptorStatusToken(authenticated, true, attr, object);   
         }  
      ............  
    }  
}  
 
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {  
     public void invoke(FilterInvocation fi) throws IOException, ServletException {  
        if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)  
            && observeOncePerRequest) {  
             
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
        } else {  
             
            if (fi.getRequest() != null) {  
                fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);  
            }  
 
            InterceptorStatusToken token = super.beforeInvocation(fi);  
 
            try {  
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
            } finally {  
                super.afterInvocation(token, null);  
            }  
        }  
    }  
    ............  
}  
 
public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {      
    public Object invoke(MethodInvocation mi) throws Throwable {  
        Object result = null;  
        InterceptorStatusToken token = super.beforeInvocation(mi);  
 
        try {  
            result = mi.proceed();  
        } finally {  
            result = super.afterInvocation(token, result);  
        }  
 
        return result;  
    }  
    ............  
}  
 
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {  
     public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {  
        Object result = null;  
        InterceptorStatusToken token = super.beforeInvocation(jp);  
 
        try {  
            result = advisorProceed.proceedWithObject();  
        } finally {  
            result = super.afterInvocation(token, result);  
        }  
 
        return result;  
    }  
    ............  



上面的代码片断已经显示,所有的真正参与验证的代码都在父类AbstractSecurityInterceptor.beforeInvocation()之中进行,而对于拦截器都只是做些委托罢了。这样可以把具体的验证代码同拦截器分开,也有利于扩展,用其他的aop技术或拦截器进行扩展,可以很轻松。

认证体系由AuthenticationManager负责,授权体系由AccessDecisionManager负责,RunAsManager 是作为用户身份转换的手段。AfterInvocationManager留下了一个接口,可以扩展默认的授权体系,可以做一些其他额外的工作。

在AbstractSecurityInterceptor.beforeInvocation()中,
首先进行认证,authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext().getAuthentication());
其次进行授权,this.accessDecisionManager.decide(authenticated, object, attr);

AbstractSecurityInterceptor.afterInvocation()中,
做其他扩展,returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),token.getAttr(), returnedObject);

2,认证体系
2.1认证管理器
认证体系的核心为AuthenticationManager,他的方法authenticate(Authentication authentication)负责所有的认证。在acegi中,由具体类ProviderManager来进行认证过程。


代码
public interface AuthenticationManager {  
    public Authentication authenticate(Authentication authentication)  
        throws AuthenticationException;  
}  
 
public abstract class AbstractAuthenticationManager  
    implements AuthenticationManager{  
    public final Authentication authenticate(Authentication authRequest)  
        throws AuthenticationException {  
        try {  
            Authentication authResult = doAuthentication(authRequest);  
            copyDetails(authRequest, authResult);  
 
            return authResult;  
        } catch (AuthenticationException e) {  
            e.setAuthentication(authRequest);  
            throw e;  
        }  
    }  
 
    private void copyDetails(Authentication source, Authentication dest) {  
        if ((dest instanceof AbstractAuthenticationToken) && (dest.getDetails() == null)) {  
            AbstractAuthenticationToken token = (AbstractAuthenticationToken) dest;  
 
            token.setDetails(source.getDetails());  
        }  
    }  
 
    protected abstract Authentication doAuthentication(Authentication authentication)  
        throws AuthenticationException;  
 
    .........  
}  
 
public class ProviderManager extends AbstractAuthenticationManager implements InitializingBean,  
    ApplicationEventPublisherAware, MessageSourceAware {  
    private List providers;  
    ............  
    public Authentication doAuthentication(Authentication authentication)  
        throws AuthenticationException {  
     .........  
        Iterator iter = providers.iterator();  
        ............  
        while (iter.hasNext()) {  
            .............  
            AuthenticationProvider provider = (AuthenticationProvider) iter.next();  
            .........  
            result = provider.authenticate(authentication);  
            ............  
        }  
        ............  
    }  
    .........  



从上面代码片断可以看出,真正的认证过程是在ProviderManager.doAuthentication()中进行的。而ProviderManager并不是具体的认证者,他只是个管理器,它要将具体的认证过程委托给具体的认证器提供者AuthenticationProvider去做。

2.2认证提供者
认证提供者就有很多了,可以提供各种各样的认证。如dao,ldap,anonymous,authbyadapter,cas,jaas,remeberme,remote,runnasimpl,testing,x509等。


代码
public interface AuthenticationProvider {  
    public Authentication authenticate(Authentication authentication) throws AuthenticationException;  
    public boolean supports(Class authentication);  



具体的认证提供者类就不详细分析了,只提个名字:DaoAuthenticationProvider,LdapAuthenticationProvider,AnonymousAuthenticationProvider,AuthByAdapterProvider,CasAuthenticationProvider,JaasAuthenticationProvider,RememberMeAuthenticationProvider,RemoteAuthenticationProvider,RunAsImplAuthenticationProvider,TestingAuthenticationProvider,X509AuthenticationProvider。

3,授权体系
3.1授权管理器
授权体系的核心为授权管理器(AccessDecisionManager),它的方法decide(Authentication authentication, Object object, ConfigAttributeDefinition config)进行具体的授权动作。


代码
public interface AccessDecisionManager {  
     
    public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)  
        throws AccessDeniedException, InsufficientAuthenticationException;  
    public boolean supports(ConfigAttribute attribute);  
    public boolean supports(Class clazz);  
}  
 
public abstract class AbstractAccessDecisionManager implements AccessDecisionManager, InitializingBean,  
    MessageSourceAware {  
    private List decisionVoters;  
    protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();  
    private boolean allowIfAllAbstainDecisions = false;  
 
    public boolean supports(ConfigAttribute attribute) {  
        Iterator iter = this.decisionVoters.iterator();  
 
        while (iter.hasNext()) {  
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();  
 
            if (voter.supports(attribute)) {  
                return true;  
            }  
        }  
 
        return false;  
    }  
 
    public boolean supports(Class clazz) {  
        Iterator iter = this.decisionVoters.iterator();  
 
        while (iter.hasNext()) {  
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();  
 
            if (!voter.supports(clazz)) {  
                return false;  
            }  
        }  
 
        return true;  
    }  
    ..............  
}  
 
public class AffirmativeBased extends AbstractAccessDecisionManager {  
    public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)  
        throws AccessDeniedException {  
        Iterator iter = this.getDecisionVoters().iterator();  
        int deny = 0;  
 
        while (iter.hasNext()) {  
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();  
            int result = voter.vote(authentication, object, config);  
 
            switch (result) {  
            case AccessDecisionVoter.ACCESS_GRANTED:  
                return;  
 
            case AccessDecisionVoter.ACCESS_DENIED:  
                deny++;  
 
                break;  
 
            default:  
                break;  
            }  
        }  
 
        if (deny > 0) {  
            throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",  
                    "Access is denied"));  
        }  
 
        // To get this far, every AccessDecisionVoter abstained  
        checkAllowIfAllAbstainDecisions();  
    }  
    ..............  
}  
 
public class ConsensusBased extends AbstractAccessDecisionManager {  
    public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)  
        throws AccessDeniedException {  
        Iterator iter = this.getDecisionVoters().iterator();  
        int grant = 0;  
        int deny = 0;  
        int abstain = 0;  
 
        while (iter.hasNext()) {  
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();  
            int result = voter.vote(authentication, object, config);  
 
            switch (result) {  
            case AccessDecisionVoter.ACCESS_GRANTED:  
                grant++;  
 
                break;  
 
            case AccessDecisionVoter.ACCESS_DENIED:  
                deny++;  
 
                break;  
 
            default:  
                abstain++;  
 
                break;  
            }  
        }  
 
        if (grant > deny) {  
            return;  
        }  
 
        if (deny > grant) {  
            throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",  
                    "Access is denied"));  
        }  
 
        if ((grant == deny) && (grant != 0)) {  
            if (this.allowIfEqualGrantedDeniedDecisions) {  
                return;  
            } else {  
                throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",  
                        "Access is denied"));  
            }  
        }  
 
        // To get this far, every AccessDecisionVoter abstained  
        checkAllowIfAllAbstainDecisions();  
    }  
    ..............  
}  
 
public class UnanimousBased extends AbstractAccessDecisionManager {  
    public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)  
        throws AccessDeniedException {  
        int grant = 0;  
        int abstain = 0;  
 
        Iterator configIter = config.getConfigAttributes();  
 
        while (configIter.hasNext()) {  
            ConfigAttributeDefinition thisDef = new ConfigAttributeDefinition();  
            thisDef.addConfigAttribute((ConfigAttribute) configIter.next());  
 
            Iterator voters = this.getDecisionVoters().iterator();  
 
            while (voters.hasNext()) {  
                AccessDecisionVoter voter = (AccessDecisionVoter) voters.next();  
                int result = voter.vote(authentication, object, thisDef);  
 
                switch (result) {  
                case AccessDecisionVoter.ACCESS_GRANTED:  
                    grant++;  
 
                    break;  
 
                case AccessDecisionVoter.ACCESS_DENIED:  
                    throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",  
                            "Access is denied"));  
 
                default:  
                    abstain++;  
 
                    break;  
                }  
            }  
        }  
 
        // To get this far, there were no deny votes  
        if (grant > 0) {  
            return;  
        }  
 
        // To get this far, every AccessDecisionVoter abstained  
        checkAllowIfAllAbstainDecisions();  
    }  
    ..............  



授权管理器AccessDecisionManager默认有三个实现,具体为AffirmativeBased,ConsensusBased,UnanimousBased。三个具体实现都大同小异,主要在具有角色是否应该授权上。
而具体能否单个角色是否授权,是委派给AccessDecisionVoter去做的。

3.2授权投票者
授权投票责的核心是接口AccessDecisionVoter。他有几个具体实现类:BasicAclEntryVoter,AuthenticatedVoter,RoleVoter。


代码
public interface AccessDecisionVoter {  
     
    public static final int ACCESS_GRANTED = 1;  
    public static final int ACCESS_ABSTAIN = 0;  
    public static final int ACCESS_DENIED = -1;  
 
    public boolean supports(ConfigAttribute attribute);  
    public boolean supports(Class clazz);  
    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);  
}  
 
public abstract class AbstractAclVoter implements AccessDecisionVoter {  
    public boolean supports(Class clazz) {  
        if (MethodInvocation.class.isAssignableFrom(clazz)) {  
            return true;  
        } else if (JoinPoint.class.isAssignableFrom(clazz)) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
    ............  
}  
 
public class BasicAclEntryVoter extends AbstractAclVoter implements InitializingBean {    
    private AclManager aclManager;  
    private String internalMethod;  
    private String processConfigAttribute;  
    private int[] requirePermission;  
 
    public boolean supports(ConfigAttribute attribute) {  
        if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getProcessConfigAttribute())) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
 
    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {  
        Iterator iter = config.getConfigAttributes();  
 
        while (iter.hasNext()) {  
            ConfigAttribute attr = (ConfigAttribute) iter.next();  
 
            if (this.supports(attr)) {  
                // Need to make an access decision on this invocation  
                // Attempt to locate the domain object instance to process  
                Object domainObject = getDomainObjectInstance(object);  
 
                // If domain object is null, vote to abstain  
                if (domainObject == null) {  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Voting to abstain - domainObject is null");  
                    }  
 
                    return AccessDecisionVoter.ACCESS_ABSTAIN;  
                }  
 
                // Evaluate if we are required to use an inner domain object  
                if ((internalMethod != null) && !"".equals(internalMethod)) {  
                    try {  
                        Class clazz = domainObject.getClass();  
                        Method method = clazz.getMethod(internalMethod, new Class[] {});  
                        domainObject = method.invoke(domainObject, new Object[] {});  
                    } catch (NoSuchMethodException nsme) {  
                        throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()  
                            + "' does not provide the requested internalMethod: " + internalMethod);  
                    } catch (IllegalAccessException iae) {  
                        if (logger.isDebugEnabled()) {  
                            logger.debug("IllegalAccessException", iae);  
 
                            if (iae.getCause() != null) {  
                                logger.debug("Cause: " + iae.getCause().getMessage(), iae.getCause());  
                            }  
                        }  
 
                        throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod  
                            + " for object: " + domainObject);  
                    } catch (InvocationTargetException ite) {  
                        if (logger.isDebugEnabled()) {  
                            logger.debug("InvocationTargetException", ite);  
 
                            if (ite.getCause() != null) {  
                                logger.debug("Cause: " + ite.getCause().getMessage(), ite.getCause());  
                            }  
                        }  
 
                        throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod  
                            + " for object: " + domainObject);  
                    }  
                }  
 
                // Obtain the ACLs applicable to the domain object  
                AclEntry[] acls = aclManager.getAcls(domainObject, authentication);  
 
                // If principal has no permissions for domain object, deny  
                if ((acls == null) || (acls.length == 0)) {  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Voting to deny access - no ACLs returned for this principal");  
                    }  
 
                    return AccessDecisionVoter.ACCESS_DENIED;  
                }  
 
                // Principal has some permissions for domain object, check them  
                for (int i = 0; i < acls.length; i++) {  
                    // Locate processable AclEntrys  
                    if (acls[i] instanceof BasicAclEntry) {  
                        BasicAclEntry processableAcl = (BasicAclEntry) acls[i];  
 
                        // See if principal has any of the required permissions  
                        for (int y = 0; y < requirePermission.length; y++) {  
                            if (processableAcl.isPermitted(requirePermission[y])) {  
                                if (logger.isDebugEnabled()) {  
                                    logger.debug("Voting to grant access");  
                                }  
 
                                return AccessDecisionVoter.ACCESS_GRANTED;  
                            }  
                        }  
                    }  
                }  
 
                // No permissions match  
                if (logger.isDebugEnabled()) {  
                    logger.debug(  
                        "Voting to deny access - ACLs returned, but insufficient permissions for this principal");  
                }  
 
                return AccessDecisionVoter.ACCESS_DENIED;  
            }  
        }  
 
        return AccessDecisionVoter.ACCESS_ABSTAIN;  
    }  
    ...............  
}  
 
public class AuthenticatedVoter implements AccessDecisionVoter {  
 
    public static final String IS_AUTHENTICATED_FULLY = "IS_AUTHENTICATED_FULLY";  
    public static final String IS_AUTHENTICATED_REMEMBERED = "IS_AUTHENTICATED_REMEMBERED";  
    public static final String IS_AUTHENTICATED_ANONYMOUSLY = "IS_AUTHENTICATED_ANONYMOUSLY";  
 
    private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();  
 
    private boolean isFullyAuthenticated(Authentication authentication) {  
        return (!authenticationTrustResolver.isAnonymous(authentication)  
        && !authenticationTrustResolver.isRememberMe(authentication));  
    }  
 
    public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {  
        Assert.notNull(authenticationTrustResolver, "AuthenticationTrustResolver cannot be set to null");  
        this.authenticationTrustResolver = authenticationTrustResolver;  
    }  
 
    public boolean supports(ConfigAttribute attribute) {  
        if ((attribute.getAttribute() != null)  
            && (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())  
            || IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())  
            || IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute()))) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
 
    public boolean supports(Class clazz) {  
        return true;  
    }  
 
    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {  
        int result = ACCESS_ABSTAIN;  
        Iterator iter = config.getConfigAttributes();  
 
        while (iter.hasNext()) {  
            ConfigAttribute attribute = (ConfigAttribute) iter.next();  
 
            if (this.supports(attribute)) {  
                result = ACCESS_DENIED;  
 
                if (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())) {  
                    if (isFullyAuthenticated(authentication)) {  
                        return ACCESS_GRANTED;  
                    }  
                }  
 
                if (IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())) {  
                    if (authenticationTrustResolver.isRememberMe(authentication)  
                        || isFullyAuthenticated(authentication)) {  
                        return ACCESS_GRANTED;  
                    }  
                }  
 
                if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) {  
                    if (authenticationTrustResolver.isAnonymous(authentication) || isFullyAuthenticated(authentication)  
                        || authenticationTrustResolver.isRememberMe(authentication)) {  
                        return ACCESS_GRANTED;  
                    }  
                }  
            }  
        }  
 
        return result;  
    }  
}  
 
public class RoleVoter implements AccessDecisionVoter {  
    private String rolePrefix = "ROLE_";  
 
    public boolean supports(ConfigAttribute attribute) {  
        if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
 
    public boolean supports(Class clazz) {  
        return true;  
    }  
 
    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {  
        int result = ACCESS_ABSTAIN;  
        Iterator iter = config.getConfigAttributes();  
 
        while (iter.hasNext()) {  
            ConfigAttribute attribute = (ConfigAttribute) iter.next();  
 
            if (this.supports(attribute)) {  
                result = ACCESS_DENIED;  
 
                for (int i = 0; i < authentication.getAuthorities().length; i++) {  
                    if (attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())) {  
                        return ACCESS_GRANTED;  
                    }  
                }  
            }  
        }  
        return result;  
    }  



这三个授权投票实现类中 acl 又最复杂。他会委托给acl管理器(AclManager)来做具体的授权工作。

3.3acl授权体系
AclManager只有一个实现类AclProviderManager ,负责提供acl授权实体。


代码
public interface AclManager {  
     
    public AclEntry[] getAcls(Object domainInstance);  
    public AclEntry[] getAcls(Object domainInstance, Authentication authentication);  
}  
 
public class AclProviderManager implements AclManager, InitializingBean {    
    public AclEntry[] getAcls(Object domainInstance) {  
        Assert.notNull(domainInstance, "domainInstance is null - violating interface contract");  
 
        Iterator iter = providers.iterator();  
 
        while (iter.hasNext()) {  
            AclProvider provider = (AclProvider) iter.next();  
 
            if (provider.supports(domainInstance)) {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("ACL lookup using " + provider.getClass().getName());  
                }  
 
                return provider.getAcls(domainInstance);  
            }  
        }  
 
        if (logger.isDebugEnabled()) {  
            logger.debug("No AclProvider found for " + domainInstance.toString());  
        }  
 
        return null;  
    }  
 
    public AclEntry[] getAcls(Object domainInstance, Authentication authentication) {  
        Assert.notNull(domainInstance, "domainInstance is null - violating interface contract");  
        Assert.notNull(authentication, "authentication is null - violating interface contract");  
 
        Iterator iter = providers.iterator();  
 
        while (iter.hasNext()) {  
            AclProvider provider = (AclProvider) iter.next();  
 
            if (provider.supports(domainInstance)) {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("ACL lookup using " + provider.getClass().getName());  
                }  
 
                return provider.getAcls(domainInstance, authentication);  
            } else {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Provider " + provider.toString() + " does not support " + domainInstance);  
                }  
            }  
        }  
 
        if (logger.isDebugEnabled()) {  
            logger.debug("No AclProvider found for " + domainInstance.toString());  
        }  
 
        return null;  
    }  
    .........  

分享到:
评论

相关推荐

    DWR中文文档v0.9

    - **4.8 DWR与Acegi** - 解释了如何解决DWR和Acegi(Spring Security的前身)之间的安全性问题。 #### 第5章:DWR中的JavaScript简介 - **5.1 简单的回调函数** - 通过示例演示了如何使用简单的回调函数来处理异步...

    同步电机无传感HFI高频谐波注入模型及代码解析,PMSM永磁同步电机滑模观测器仿真模型研究,基于28035的典型HFI方案实现,详细解析参数实现过程与机理,工程实践与理论基础相结合的SOP代码应用,基

    同步电机无传感HFI高频谐波注入模型及代码解析,PMSM永磁同步电机滑模观测器仿真模型研究,基于28035的典型HFI方案实现,详细解析参数实现过程与机理,工程实践与理论基础相结合的SOP代码应用,基于无传感HFI高频谐波注入模型的PMSM永磁同步电机同步控制技术:解析与代码实现,同步电机无传感HFI高频谐波注入模型+代码 PMSM永磁同步电机无传感器滑模观测器仿真模型(基于28035),典型的HFI方案; 代码为实际应用SOP代码,非一般玩票代码可比(非ti例程);解析说明详细描述了参数实现过程和实现机理,工程实践和理论基础结合。 ,核心关键词:同步电机;无传感HFI高频谐波注入模型;PMSM永磁同步电机;滑模观测器;仿真模型;28035;HFI方案;SOP代码;参数实现过程;实现机理;工程实践;理论基础。,基于HFI高频谐波注入的PMSM无传感器控制模型与SOP代码实现

    基于thinkphp3.2开发的商城系统

    一个采用thinkphp3.2开发的商城系统,无论从前台模板的设计,还是后台php的开,都具有非常好的学习价值。首先作为一套前台模板框架的学习总结成果。.zip项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    无人驾驶车辆动力学模型验证与预测控制资料详解:视频教程及carsim2019与matlab2018应用,无人驾驶车辆动力学模型验证与预测控制资料详解:视频教程及carsim2019与matlab201

    无人驾驶车辆动力学模型验证与预测控制资料详解:视频教程及carsim2019与matlab2018应用,无人驾驶车辆动力学模型验证与预测控制资料详解:视频教程及carsim2019与matlab2018应用,无人驾驶的车辆动力学模型验证。 配套详细视频讲解。 配套无人驾驶车辆模型预测控制资料,有视频讲解carsim2019,matlab2018 ,无人驾驶车辆动力学模型验证;配套视频讲解;无人驾驶车辆模型预测控制;carsim2019视频讲解;matlab2018资料,无人驾驶车辆动力学模型验证与MPC控制技术详解视频

    基于vue+elment-ui+node.js的后台管理系统 .zip(毕设&课设&实训&大作业&竞赛&项目)

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    **基于多维度仿真的质子交换膜燃料电池模型构建与性能研究**,基于电化学经验模型与车辆参数,质子交换膜燃料电池稳态与动态建模仿真分析及特性研究,质子交膜燃料电池(#PEMFC) 稳态 AND 动态建模

    **基于多维度仿真的质子交换膜燃料电池模型构建与性能研究**,基于电化学经验模型与车辆参数,质子交换膜燃料电池稳态与动态建模仿真分析及特性研究,质子交膜燃料电池(#PEMFC) 稳态 AND 动态建模及仿真分析 Note:硕士lunwen复Xian;title:质子交膜燃料电池建模仿真与特性研究 内容: 1. 根据车辆结构参数和性能参数 确定燃料电池组相关参数, eg. 额定功率,最大功率等. (根据需求可省略,或改进); 2. 基于电化学经验模型,建立PEMFC 燃料电池的稳态数学模型; 3. 在稳态数学模型的基础上,考虑燃料电池双层电荷层现象以及电池电堆动态热传输的影响,建立PEMFC 电化学动态模型; 4. 建立稳态 AND 动态Simulink仿真模型; 5. 通过Signal Builder 模拟随时间阶跃下降的外加负载信号,Simulink仿真燃料电池的输出电压,输出功率,消耗功率,电池效率的变化曲线, 并详细分析了电池的稳态 动态响应特性以及影响因素; 6. 极其详尽的模型说明书(包含数学建模,simulink建模,模型结果分析,etc.) AND 图

    基于JavaWeb的求职招聘管理信息系统的设计与实现.zip

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    学习资料-YOLOV5目标检测全套视频课程-共7课.zip

    推荐,YOLOV5目标检测全套视频课程,共7节。 1.任务需求与项目概述.mp4 2-数据与标签配置方法.mp4 3-标签转格式脚本制作.mp4 4-各版本模型介绍.mp4 5-项目参数配置.mp4 6-缺陷检测模型培训.mp4 7-输出结果与项目总结.mp4

    智慧农业解决方案 -促进产业结构转型,突破传统业态.ppt

    智慧农业解决方案 -促进产业结构转型,突破传统业态.ppt

    西门子200smart与昆仑通态锅炉换热站智能控制程序实例:涵盖模拟量读取、自动切换控制、时间段加热与温度设定、电能监控及Modbus通讯变频器控制 ,西门子200smart与昆仑通态锅炉换热站程序实

    西门子200smart与昆仑通态锅炉换热站智能控制程序实例:涵盖模拟量读取、自动切换控制、时间段加热与温度设定、电能监控及Modbus通讯变频器控制。,西门子200smart与昆仑通态锅炉换热站程序实例:模拟量读取、自动切换与时间加热控制,Modbus通讯变频器电能管理解决方案,西门子200smart和昆仑通态锅炉热站程序项目实例,程序内有利用模拟量读取,运算时间自动切,水泵一用一备故障自动切,自动时间段加热,时间段设定温度,电能读取及算法 modbus通讯控制变频器。 ,核心关键词: 西门子200smart; 昆仑通态锅炉; 换热站程序项目; 模拟量读取; 运算时间自动切换; 水泵一用一备故障自动切换; 自动时间段加热; 设定温度; 电能读取; 算法; Modbus通讯; 控制变频器。,西门子Smart200程序控制锅炉换热站:智能换热与节能优化管理实例

    基于HTML5+CSS3+jquery实现音乐播放器.zip(毕设&课设&实训&大作业&竞赛&项目)

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    相移格雷码解相位程序开发与条纹结构光编解码技术应用于单双目结构光三维重建系统,相移格雷码解相位程序开发:条纹结构光编解码技术助力单目双目结构光三维重建系统,相移格雷码解相位程序开发 条纹结构光编解码

    相移格雷码解相位程序开发与条纹结构光编解码技术应用于单双目结构光三维重建系统,相移格雷码解相位程序开发:条纹结构光编解码技术助力单目双目结构光三维重建系统,相移格雷码解相位程序开发 条纹结构光编解码,可用于单目或双目结构光三维重建系统 ,相移格雷码解相位程序开发; 结构光编解码; 单目结构光; 双目结构光; 三维重建系统,相移格雷码解相位程序开发:单目双目结构光三维重建系统编解码技术

    高集成伺服电机驱控芯片TMC9660例子代码

    高集成伺服电机驱控芯片TMC9660例子代码

    个人博客系统,使用Springboot,SpringDataJpa,Redis,RabbitMQ.zip(毕设&课设&实训&大作业&竞赛&项目)

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    基于任务链的中小工厂数字化新路径 高效搭建有竞争力的数字工厂.pptx

    基于任务链的中小工厂数字化新路径 高效搭建有竞争力的数字工厂.pptx

    光伏并网逆变器设计方案与高效实现:结合matlab电路仿真、DSP代码及环流抑制策略,光伏并网逆变器设计方案:结合matlab电路文件与DSP程序代码,实现高效并联环流抑制策略,光伏并网逆变器设计方案

    光伏并网逆变器设计方案与高效实现:结合matlab电路仿真、DSP代码及环流抑制策略,光伏并网逆变器设计方案:结合matlab电路文件与DSP程序代码,实现高效并联环流抑制策略,光伏并网逆变器设计方案,附有相关的matlab电路文件,以及DSP的程序代码,方案、仿真文件、代码三者结合使用效果好,事半功倍。 备注:赠送逆变器并联环流matlab文件,基于矢量控制的环流抑制策略和下垂控制的环流抑制 ,光伏并网逆变器设计方案; MATLAB电路文件; DSP程序代码; 方案、仿真文件、代码结合使用; 并联环流抑制策略; 下垂控制的环流抑制,光伏并网逆变器优化设计:方案、仿真与DSP程序代码三合一,并赠送并联环流抑制策略Matlab文件

    基于jsp+servlet设计的ECSHOP商城二次开发.zip

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    校园在线拍卖系统(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计

    校园在线拍卖系统(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 【功能需求】 按照校园在线拍卖系统的角色,我划分为了用户模块(拍卖者和用户)和管理员模块这两大部分。 拍卖者模块: (1)注册登录:用户注册为会员并登录校园在线拍卖系统;用户对个人信息的增删改查,比如个人资料,密码修改。 (2)竞拍商品管理:拍卖者可以对竞拍商品进行增删改查。 (3)竞拍订单管理:拍卖者可以看到用户提交的竞拍价格信息以及产品,可以对竞拍订单进行审核。 (4)评价订单管理:可以在此页面查看到用户提交的订单评价信息等。 (5)在线留言:可以回复用户的在线留言信息。 用户模块: (1)用户注册登录:用户注册为会员并登录校园在线拍卖系统;用户对个人信息的增删改查,比如个人资料,密码修改。 (2)拍卖资讯:用户可以在此模块中浏览系统发布的最新拍卖资讯。 (3)竞拍商品:用户可以查看到竞拍商品详情。 (4)在线竞拍:用户可以在竞拍商品下方点击立即竞拍,提交竞拍信息。 (5)在线留言:用户可以提交在线留言信息。 (6)竞拍订单:可以在线进行竞拍商品订单的支付。 (7)评价订单:支付后可以对订单进行评价。 管理员管理模块: (1)用户管理:管理员可以对前台上注册过的用户信息进行管控,对拍卖者信息进行审核,也可以对管理员信息进行管控。 (2)用户管理:管理员对系统用户的管理。 (3)商品分类管理:对商品进行分类管理。 (4)竞拍商品管理:对拍卖者发布的拍卖商品进行管理。 (5)竞拍订单管理:对用户提交的竞拍订单信息进行管理。 (6)评价订单管理:对用户的评价信息进行管理。 (7)在线留言管理:对用户的留言信息进行管理。 (8)系统管理:对通知公告、竞拍资讯、轮播图管理。 【环境需要】 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.数据库:MySql 5.7/8.0等版本均可; 【购买须知】 本源码项目经过严格的调试,项目已确保无误,可直接用于课程实训或毕业设计提交。里面都有配套的运行环境软件,讲解视频,部署视频教程,一应俱全,可以自己按照教程导入运行。附有论文参考,使学习者能够快速掌握系统设计和实现的核心技术。

    基于SSM+JSP的国学文化网站的设计与实现.zip

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    二极管箝位型三电平逆变器与NPC三电平逆变器的SVPWM及中点电位平衡调制研究-基于MATLAB Simulink仿真模型,二极管箝位型与NPC三电平逆变器研究:SVPWM及中点电位平衡调制的技术挑

    二极管箝位型三电平逆变器与NPC三电平逆变器的SVPWM及中点电位平衡调制研究——基于MATLAB Simulink仿真模型,二极管箝位型与NPC三电平逆变器研究:SVPWM及中点电位平衡调制的技术挑战与MATLAB仿真模型参考,二极管箝位型三电平逆变器,NPC三电平逆变器。 主要难点:三电平空间矢量调制(SVPWM),中点电位平衡调制等。 MATLAB Simulink仿真模型,可提供参考文献。 ,二极管箝位; NPC三电平; 三电平空间矢量调制(SVPWM); 中点电位平衡调制; MATLAB Simulink仿真模型,三电平逆变器技术研究:SVPWM调制与中点电位平衡仿真分析

Global site tag (gtag.js) - Google Analytics