- 浏览: 73208 次
- 性别:
-
文章分类
最新评论
-
yehayeah:
ljm653467 写道 嗯,很好,可以借鉴,不过我想问的是在 ...
转载:单例设计模式中使用dom4j来完成(数据库配置文件)xml的解析,并完成数据库的连接 -
ljm653467:
嗯,很好,可以借鉴,不过我想问的是在你上面的代码基础上,如果我 ...
转载:单例设计模式中使用dom4j来完成(数据库配置文件)xml的解析,并完成数据库的连接
转载自:http://blog.csdn.net/tancaiyi/article/details/3971585
声明:本人转载只为分享,如涉及商业版权纠纷,请及时与本人联系,必将立即删除,造成不便,还望见谅,谢谢。
Java平台是创建企业应用程序的普遍选择。它所以受欢迎,主要原因之一是在创建Java语言时充分考虑了安全性,而且市场上也普遍认为Java是一种"安全的"语言。Java平台在两个层次上提供安全性:语言层次安全性和企业层次安全性。
1.语言层次安全性
最初的Java(JDK1.2)平台采用沙箱安全模型,基本安全模型由三部分来承担,这三部分构成Java运行环境的三个安全组件,分别是:类加载器,文件校验器,安全管理器
1.1类加载器
类加载器负责从特定位置加载类,类加载器是JVM的看门人,控制着哪些代码被加载或被拒绝,类加载器首先进行安全性检查,它往往从以下几个方面去检查,装入的字节码是否生成指针,装入的字节码是否违反访问限制,装入的字节码是否把对象当作它们本身来访问,它在确保执行代码的安全性方面至关重要。
1.2类文件校验器的校验
类文件校验器负责检查那些无法执行的明显有破坏性的操作,类文件校验器执行的一些检查通常有:变量要在使用之前进行初始化;方法调用和对象引用类型之间要匹配;没有违反访问私有数据和方法的规则;对本地变量的访问都在运行时堆栈内;运行时堆栈是否溢出.如果以上检查中任何一条没有通过,就认为该类遭到了破坏,不被加载。
1.3安全管理器
一旦某个类被类加载器加载到虚拟机中,并由类文件校验器检查过之后,JAVA的第三种安全机制安全管理器就会启动,安全管理器是一个负责控制某个操作是否允许执行的类,安全管理器负责检查包括以下几个方面的操作:当前线程是否能创建一个新的类加载器;当前线程是否能终止JVM的运行;某个类是否能访问另一个类的成员;当前线程是否能访问本地文件;当前线程是否能打开到达外部记住的socket连接;某个类是否能启动打印作业;某个类是否能访问系统剪贴板;某个类是否能访问AWT事件队列;当前线程是否可被信任以打开一顶层窗口。
尽管Java安全的支柱类加载器、类文件校验器、安全管理器每一个都有独特的功能,但它们又相互依赖、相辅相承。共同保证了Java语言的安全性。
2.企业层次的安全特性
即是构建安全的J2EE应用。Java平台在提供语言安全性的同时还提供其他API功能,为企业应用程序提供一个总体的安全性解决方案。下面将介绍几种方案。
2.1 Java加密扩展(JCE)
JCE是一组包,为加密、密钥生成、密钥协商和消息身份验证代码(MAC)算法提供一种框架和实现。JCE支持多种类型的加密,包括对称的、非对称的、块和流密码。在JDK 1.4之前,JCE是一个可选的包,现在它已经成为Java平台的一个标准组成部分。
2.2 Java安全套接字扩展(JSSE)
JSSE是支持安全的Internet通信的一组包。它是实现了SSL和传输层安全(TLS)协议的JAVA技术。它包括用于数据加密、服务器身份验证、消息完整性和可选的客户端身份验证的诸多功能。JSSE已被集成到JDK 1.4以上版本的平台中。
2.3 Java身份验证和授权规范(JAAS)
JAAS通过对运行程序的用户的进行验证,从而达到保护系统的目的。JAAS主要由两个部件构成,认证和授权,JAAS通过一个配置文件来定义认证机制。认证模块是基于可插的认证模块而设计的,它可以运行在客户端和服务器端,授权模块的设计是一个变化的过程,为了对资源的访问请求进行授权,首先需要应用程序认证请求的资源,subject术语来表示请求的资源,用java.security.auth.Subject类来表示subject。subject一旦通过了认证,就会和身份和主体想关联。在JAAS中将主体表示为javax.security.Principal对象,一个subject可能包含多个主题,除了和主题相关联外,subject还可能拥有与安全相关的属性或证书,证书是用户的数据,它包含这样的认证信息即认证subject所拥有的其他服务的信息。基于J2EE的分布式应用程序使用
JAAS一般有两种情况:第一种情况,一个单独的应用系统与一个远程的EJB系统连接,用户必须向应用系统提供证明身份的信息或应用系统向文件和其它的系统来检索可证明身份的信息。这个单独的应用系统将在调用EJB组件之前使用JAAS来验证用户,由应用服务器完成验证的任务。只有当用户通过JAAS的验证之后,客户端程序才可被信任地调用EJB方法。第二种情况,基于Web浏览器的客户端程序连接到Servlet/JSP层,客户端用户将向Servlet/JSP层提供证明身份的信息,而Servlet/JSP层可以采用JAAS验证用户。Web客户端一般可以采
用基本验证、基于表格的验证、摘要验证、证书验证等方式来提供证明身份的信息。这种支持选择不同认证方法的灵活性有助于支持在管理员层实施更为复杂的安全策略,而不是在编程层上去实现。一旦客户端通过应用服务器认证,安全上下文环境能被传播到EJB层。在应用程序中使用JAAS验证通常会涉及到以下几个步骤:
1.创建一个LoginContext的实例。并传递LoginModule配置
文件程序段和CallbackHandler的名称。
2.为了能够获得和处理验证信息,将一个CallbackHandler
对象作为参数传送给LoginContext。
3.通过调用LoginContext的login()方法来进行验证。
4.通过使用login()方法返回的Subject对象实现一些特殊
的功能(假设登录成功)。
举个例子:
LoginModel是jaas的一个核心接口,她负责实施用户认证。同时暴漏了initialize(),login(),commit(),abort(),logout()方法。
package sample;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class ScreenContentLoginModule implements LoginModule {
protected static final Log log = LogFactory.getLog(ScreenContentLoginModule.class);
private Subject subject;
private UsernamePasswordPrincipal principal;
private CallbackHandler callbackhandler;
public ScreenContentLoginModule() {
log.info("ScreenContentLoginModule()................");
}
//在初始化LoginModel后,LoginContext会调用这一方法,从而完成当前LoginModel的初始化工作
public void initialize(Subject subject, CallbackHandler
callbackhandler, Map state, Map options) {
log.info("进入initialize()................");
this.principal = null;
this.subject = subject;
this.callbackhandler = callbackhandler;
}
//用户阶段1,并认证subject的方法,它可能会收集用户的凭证,比如用户名,密码,并将认证结果存储到LoginModel的实例中
public boolean login() throws LoginException {
log.info("进入login()................");
Callback callbacks[] = new Callback[2];
callbacks[0] = new NameCallback("您的登录名:");
callbacks[1] = new PasswordCallback("您的密码:", false);
String username = null;
String password = null;
try {
this.callbackhandler.handle(callbacks);
username = ((NameCallback) callbacks[0]).getName();
password = new String(((PasswordCallback) callbacks[1]).getPassword());
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException ce) {
throw new LoginException(ce.getCallback().toString());
}
if (username.equals("marissa") || username.equals("scott")) {
this.principal = new UsernamePasswordPrincipal(username,password);
return true;
} else {
return false;
}
}
//表明认证操作成功,会获得阶段1(login())的认证结果,并将这一结果填充到subject中
public boolean commit() throws LoginException {
log.info("进入commit()................");
if(this.principal == null)
return false;
this.subject.getPrincipals().add(this.principal);
return true;
}
//认证操作失败
public boolean abort() throws LoginException {
log.info("进入abort()................");
if(this.principal == null)
return false;
this.principal = null;
return true;
}
//完成subject的销毁工作
public boolean logout() throws LoginException {
log.info("进入logout()................");
if(this.principal == null)
return false;
this.subject.getPrincipals().remove(principal);
this.principal = null;
return true;
}
}
下面是UsernamePasswordCallbackhandler类:
package sample;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class UsernamePasswordCallbackHandler implements CallbackHandler {
protected static final Log log = LogFactory.getLog(UsernamePasswordCallbackHandler.class);
public void handle(Callback callbacks[]) throws IOException, UnsupportedCallbackException {
log.info("进入handle()........................");
for (Callback cb: callbacks) {
if (cb instanceof NameCallback) {
NameCallback nc = (NameCallback) cb;
log.info(nc.getPrompt());
//采集用户名
String username = (new BufferedReader(new InputStreamReader(
System.in))).readLine();
nc.setName(username);
} else if(cb instanceof PasswordCallback){
PasswordCallback pc = (PasswordCallback) cb;
log.info(pc.getPrompt());
//采集用户密码
String password = (new BufferedReader(new InputStreamReader(
System.in))).readLine();
pc.setPassword(password.toCharArray());
}
}
}
}
一旦用户收集到用户账号后NameCallback,PasswordCallback对象都会存储他们,与此同时,上述login()方法会基于账号信构建UsernamePasswordPrincipal对象,并保留在登录模块中,而且login()会返回true,当login方法顺利完成用户凭证信息的收集工作后,commit会被触发,她将UsernamePasswordPrincipal对象摆到Subject对象中。
当login方法未能顺利完成用户凭证信息的收集工作后,abort会被触发,将principal等信息破换掉。当登录用户完满的完成自身的业务操作后便可以考虑退出当前的应用,调用logout方法。下面是Principal对象:
package sample;
import java.security.Principal;
/**
*
* @author worldheart
*
*/
//Acegi中的Authentication接口继承了Principal接口
public class UsernamePasswordPrincipal implements Principal {
private String username;
private String password;
//存储用户名、密码,比如marissa/koala
public UsernamePasswordPrincipal(String username, String password) {
this.username = username;
this.password = password;
}
public String getName() {
return this.username;
}
public String toString() {
return this.username + "->" + this.password;
}
}
为了使用上述登录模块,需要准备一个jaas配置文件:
Loginmodel.conf放在src下面
ScreenContent {
sample.ScreenContentLoginModule required;
};
客户应用:
package sample;
import java.io.File;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class JaasSecurityClient {
protected static final Log log = LogFactory
.getLog(JaasSecurityClient.class);
public static void main(String argv[]) throws LoginException,
SecurityException {
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为," + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
}
}
在运行客户应用之前还需要提供JVM参数,即引用到loginmoudel.conf配置文件:
-Djava.security.auth.login.config=src/loginmoudel.conf
或者通过javahome/jre/lib/security目录中的java.security配置文件指定上述loginmoudel.conf配置文件:
#login.config.url.l=file:${user.home}/.java.login.config
login.config.url.l=file:d:/eclipse/src/loginmoudel.conf
SecurityContextLoginModule是Acegi内置的一个LoginModel实现,当开发Jaas应用时,用户凭证信息的获取可能来自Acegi,此时,我们便可以采用内置的SecurityContextLoginModel。要使用SecurityContextLoginModule,我们需要在Jaas配置文件中配置它:
ACEGI {
org.acegisecurity.providers.jaas.SecurityContextLoginModule
required ignoreMissingAuthentication=true;
};
客户端应用:
package sample;
import java.io.File;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class AcegiSecurityClient {
protected static final Log log = LogFactory
.getLog(AcegiSecurityClient.class);
public static void main(String argv[]) throws LoginException, SecurityException {
LoginContext ctx = null;
//在实际企业应用中,Authentication对象的构建形式多种多样
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken("marissa", "koala"));
ctx = new LoginContext("ACEGI");
// marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为,"
// + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File(
// "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf")
// .exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
//清除已注册的SecurityContext
SecurityContextHolder.clearContext();
}
}
注意到我们并未为LoginContext提供CallbackHandler对象,由于Acegi负责提供兼容于Principal的Authentication对象,因此用户凭证的收集也不用CallbackHandler操心了。
在运行客户应用之前还需要提供JVM参数,即引用到loginmoudel.conf配置文件:
-Djava.security.auth.login.config=src/loginmoudel.conf
或者通过javahome/jre/lib/security目录中的java.security配置文件指定上述loginmoudel.conf配置文件:
#login.config.url.l=file:${user.home}/.java.login.config
login.config.url.l=file:d:/eclipse/src/loginmoudel.conf
启用Java安全管理器:大部分java开发者都知道,借助如下JVM参数能够启用java安全管理器,-Djava.security.manager。既然如此,我们通过如下JVM参数运行JaasSecurityClient客户端和AcegiSecurityClient客户端:
-Djava.security.manager -Djava.security.auth.login.config=src/loginmodule.conf
但是这样会出错:java.security.auth.login.config.AccessControlException:access denied
出错原因:默认时,直接借助“-Djava.security.manager”启动java安全管理器,JVM会采用javahome/jre/lib/security中的java.policy策略文件,而这一策略文件并未对上述涉及到的各种权限(比如:createLoginContext.ScreenContent,读取acegi.security.strategyJava属性)进行授权因此抛出了异常。
为此我们可以提供新的授权信息jaassecuritypolicy.txt策略文件。由于我们需要同LoginContext进行各类操作因此需要提供相关AuthPermission权限给Acegi
SecurityClient,同时我们使用了Commons-Logging,Log4j管理日志,因此还必须将相应的操作权限给这一客户,在操作日志的过程中,客户应用需要操控的:d:/ddlog.log日志文件因此需要将读写权限授给这一客户应用。
grant codebase "file:./-"{
permission java.io.FilePermission "D:/contactsforchapter8.log", "read, write";
permission javax.security.auth.AuthPermission "createLoginContext";
permission javax.security.auth.AuthPermission "modifyPrincipals";
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/log4j-1.2.14.jar" {
permission java.security.AllPermission;
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/commons-logging-1.0.4.jar" {
permission java.security.AllPermission;
};
实际上java的策略文件编写可以通过policytool工具。
运行JaasSecurityClient客户端应用:
-Djava.security.manager -Djava.security.policy=src/jaassecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
类似的运行AcegiSecurityClient的策略文件:
grant codebase "file:./-"{
permission java.util.PropertyPermission "acegi.security.strategy", "read";
permission java.io.FilePermission "D:/contactsforchapter8.log", "read, write";
permission javax.security.auth.AuthPermission "createLoginContext";
permission javax.security.auth.AuthPermission "modifyPrincipals";
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/log4j-1.2.14.jar" {
permission java.security.AllPermission;
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/commons-logging-1.0.4.jar" {
permission java.security.AllPermission;
};
运行AcegiSecurityClient客户端应用:
-Djava.security.manager -Djava.security.policy=src/acegisecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
启用Jaas的用户授权功能:jaas的授权能力依赖java策略文件,下面提供了另一个版本的jaasSecurityClient客户应用,新增了两行java代码:
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
System.getProperty("java.io.tmpdir");
// 退出当前已登录marissa用户
ctx.logout();
此时开发者必须往jaassecuritypolicy.txt策略文件中添加如下权限到其中:
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "READ";
如果客户要求只具有marissa用户才有权利运行上述两行代码,那么应该这样:
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为," + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
那么jaassecuritypolicy.txt策略文件应该添加如下内容:
grant codebase "file:./-",
Principal sample.UsernamePasswordPrincipal "marissa" {
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "READ";
};
启动jaassecurityclient客户端:
-Djava.security.manager -Djava.security.policy=src/jaassecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
那么对于acegisecurityclient客户应用,acegisecuritypolicy.txt应该增加:
grant codebase "file:./-",
Principal org.acegisecurity.providers.UsernamePasswordAuthenticationToken "marissa" {
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "read";
};
启动:
-Djava.security.manager -Djava.security.policy=src/acegisecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
直击JaasAuthenticationProvider
配置:
<bean id="jaasAuthenticationProvider" class="org.acegisecurity.providers.jaas.JaasAuthenticationProvider">
<property name="authorityGranters"
<bean class="sample.TestAuthorityGranter"/>
</property>
<property name="callbackHandlers"
<list>
<bean class="org.acegisecurity.providers.jaas.JaasNameCallbackHandler"/>
<bean class="org.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/>
</property>
<property name="loginConfig" value="classpath:acegi.conf"/>
<property name="liginContextName" value="ACEGI"/>
</bean>
另外需要将JaasAuthenticationProvider添加到认证管理器:
acegi.conf的内容:
ACEGI {
sample.TestLoginModule required;
};
注释:authorityGranters属性能够为已经认证用户提供角色映射信息,由于这里的Jaas仅负责用户认证,而授权仍然被acegi接管。TestAuthorityGranter实现类:
package sample;
import java.security.Principal;
import java.util.HashSet;
import java.util.Set;
import org.acegisecurity.providers.jaas.AuthorityGranter;
/**
*
* @author worldheart
*
*/
public class TestAuthorityGranter implements AuthorityGranter {
public Set grant(Principal principal) {
Set<String> rtnSet = new HashSet<String>();
if (principal.getName().equals("TEST_PRINCIPAL")) {
rtnSet.add("ROLE_USER");
rtnSet.add("ROLE_ADMIN");
}
return rtnSet;
}
}
下面是TestLoginModel类:
package sample;
import java.security.Principal;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
/**
*
* @author worldheart
*
*/
public class TestLoginModule implements LoginModule {
private String user;
private String password;
private Subject subject;
public boolean abort() throws LoginException {
return true;
}
public boolean commit() throws LoginException {
return true;
}
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
this.subject = subject;
try {
NameCallback nameCallback = new NameCallback("prompt");
PasswordCallback passwordCallback = new PasswordCallback("prompt",
false);
callbackHandler.handle(new Callback[] {nameCallback, passwordCallback });
user = nameCallback.getName();
password = new String(passwordCallback.getPassword());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean login() throws LoginException {
if (!user.equals("marissa")) {
throw new LoginException("用户名不对");
}
if (!password.equals("koala")) {
throw new LoginException("密码不对");
}
subject.getPrincipals().add(new Principal() {
public String getName() {
return "TEST_PRINCIPAL";
}
});
subject.getPrincipals().add(new Principal() {
public String getName() {
return "NULL_PRINCIPAL";
}
});
return true;
}
public boolean logout() throws LoginException {
return true;
}
}
声明:本人转载只为分享,如涉及商业版权纠纷,请及时与本人联系,必将立即删除,造成不便,还望见谅,谢谢。
Java平台是创建企业应用程序的普遍选择。它所以受欢迎,主要原因之一是在创建Java语言时充分考虑了安全性,而且市场上也普遍认为Java是一种"安全的"语言。Java平台在两个层次上提供安全性:语言层次安全性和企业层次安全性。
1.语言层次安全性
最初的Java(JDK1.2)平台采用沙箱安全模型,基本安全模型由三部分来承担,这三部分构成Java运行环境的三个安全组件,分别是:类加载器,文件校验器,安全管理器
1.1类加载器
类加载器负责从特定位置加载类,类加载器是JVM的看门人,控制着哪些代码被加载或被拒绝,类加载器首先进行安全性检查,它往往从以下几个方面去检查,装入的字节码是否生成指针,装入的字节码是否违反访问限制,装入的字节码是否把对象当作它们本身来访问,它在确保执行代码的安全性方面至关重要。
1.2类文件校验器的校验
类文件校验器负责检查那些无法执行的明显有破坏性的操作,类文件校验器执行的一些检查通常有:变量要在使用之前进行初始化;方法调用和对象引用类型之间要匹配;没有违反访问私有数据和方法的规则;对本地变量的访问都在运行时堆栈内;运行时堆栈是否溢出.如果以上检查中任何一条没有通过,就认为该类遭到了破坏,不被加载。
1.3安全管理器
一旦某个类被类加载器加载到虚拟机中,并由类文件校验器检查过之后,JAVA的第三种安全机制安全管理器就会启动,安全管理器是一个负责控制某个操作是否允许执行的类,安全管理器负责检查包括以下几个方面的操作:当前线程是否能创建一个新的类加载器;当前线程是否能终止JVM的运行;某个类是否能访问另一个类的成员;当前线程是否能访问本地文件;当前线程是否能打开到达外部记住的socket连接;某个类是否能启动打印作业;某个类是否能访问系统剪贴板;某个类是否能访问AWT事件队列;当前线程是否可被信任以打开一顶层窗口。
尽管Java安全的支柱类加载器、类文件校验器、安全管理器每一个都有独特的功能,但它们又相互依赖、相辅相承。共同保证了Java语言的安全性。
2.企业层次的安全特性
即是构建安全的J2EE应用。Java平台在提供语言安全性的同时还提供其他API功能,为企业应用程序提供一个总体的安全性解决方案。下面将介绍几种方案。
2.1 Java加密扩展(JCE)
JCE是一组包,为加密、密钥生成、密钥协商和消息身份验证代码(MAC)算法提供一种框架和实现。JCE支持多种类型的加密,包括对称的、非对称的、块和流密码。在JDK 1.4之前,JCE是一个可选的包,现在它已经成为Java平台的一个标准组成部分。
2.2 Java安全套接字扩展(JSSE)
JSSE是支持安全的Internet通信的一组包。它是实现了SSL和传输层安全(TLS)协议的JAVA技术。它包括用于数据加密、服务器身份验证、消息完整性和可选的客户端身份验证的诸多功能。JSSE已被集成到JDK 1.4以上版本的平台中。
2.3 Java身份验证和授权规范(JAAS)
JAAS通过对运行程序的用户的进行验证,从而达到保护系统的目的。JAAS主要由两个部件构成,认证和授权,JAAS通过一个配置文件来定义认证机制。认证模块是基于可插的认证模块而设计的,它可以运行在客户端和服务器端,授权模块的设计是一个变化的过程,为了对资源的访问请求进行授权,首先需要应用程序认证请求的资源,subject术语来表示请求的资源,用java.security.auth.Subject类来表示subject。subject一旦通过了认证,就会和身份和主体想关联。在JAAS中将主体表示为javax.security.Principal对象,一个subject可能包含多个主题,除了和主题相关联外,subject还可能拥有与安全相关的属性或证书,证书是用户的数据,它包含这样的认证信息即认证subject所拥有的其他服务的信息。基于J2EE的分布式应用程序使用
JAAS一般有两种情况:第一种情况,一个单独的应用系统与一个远程的EJB系统连接,用户必须向应用系统提供证明身份的信息或应用系统向文件和其它的系统来检索可证明身份的信息。这个单独的应用系统将在调用EJB组件之前使用JAAS来验证用户,由应用服务器完成验证的任务。只有当用户通过JAAS的验证之后,客户端程序才可被信任地调用EJB方法。第二种情况,基于Web浏览器的客户端程序连接到Servlet/JSP层,客户端用户将向Servlet/JSP层提供证明身份的信息,而Servlet/JSP层可以采用JAAS验证用户。Web客户端一般可以采
用基本验证、基于表格的验证、摘要验证、证书验证等方式来提供证明身份的信息。这种支持选择不同认证方法的灵活性有助于支持在管理员层实施更为复杂的安全策略,而不是在编程层上去实现。一旦客户端通过应用服务器认证,安全上下文环境能被传播到EJB层。在应用程序中使用JAAS验证通常会涉及到以下几个步骤:
1.创建一个LoginContext的实例。并传递LoginModule配置
文件程序段和CallbackHandler的名称。
2.为了能够获得和处理验证信息,将一个CallbackHandler
对象作为参数传送给LoginContext。
3.通过调用LoginContext的login()方法来进行验证。
4.通过使用login()方法返回的Subject对象实现一些特殊
的功能(假设登录成功)。
举个例子:
LoginModel是jaas的一个核心接口,她负责实施用户认证。同时暴漏了initialize(),login(),commit(),abort(),logout()方法。
package sample;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class ScreenContentLoginModule implements LoginModule {
protected static final Log log = LogFactory.getLog(ScreenContentLoginModule.class);
private Subject subject;
private UsernamePasswordPrincipal principal;
private CallbackHandler callbackhandler;
public ScreenContentLoginModule() {
log.info("ScreenContentLoginModule()................");
}
//在初始化LoginModel后,LoginContext会调用这一方法,从而完成当前LoginModel的初始化工作
public void initialize(Subject subject, CallbackHandler
callbackhandler, Map state, Map options) {
log.info("进入initialize()................");
this.principal = null;
this.subject = subject;
this.callbackhandler = callbackhandler;
}
//用户阶段1,并认证subject的方法,它可能会收集用户的凭证,比如用户名,密码,并将认证结果存储到LoginModel的实例中
public boolean login() throws LoginException {
log.info("进入login()................");
Callback callbacks[] = new Callback[2];
callbacks[0] = new NameCallback("您的登录名:");
callbacks[1] = new PasswordCallback("您的密码:", false);
String username = null;
String password = null;
try {
this.callbackhandler.handle(callbacks);
username = ((NameCallback) callbacks[0]).getName();
password = new String(((PasswordCallback) callbacks[1]).getPassword());
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException ce) {
throw new LoginException(ce.getCallback().toString());
}
if (username.equals("marissa") || username.equals("scott")) {
this.principal = new UsernamePasswordPrincipal(username,password);
return true;
} else {
return false;
}
}
//表明认证操作成功,会获得阶段1(login())的认证结果,并将这一结果填充到subject中
public boolean commit() throws LoginException {
log.info("进入commit()................");
if(this.principal == null)
return false;
this.subject.getPrincipals().add(this.principal);
return true;
}
//认证操作失败
public boolean abort() throws LoginException {
log.info("进入abort()................");
if(this.principal == null)
return false;
this.principal = null;
return true;
}
//完成subject的销毁工作
public boolean logout() throws LoginException {
log.info("进入logout()................");
if(this.principal == null)
return false;
this.subject.getPrincipals().remove(principal);
this.principal = null;
return true;
}
}
下面是UsernamePasswordCallbackhandler类:
package sample;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class UsernamePasswordCallbackHandler implements CallbackHandler {
protected static final Log log = LogFactory.getLog(UsernamePasswordCallbackHandler.class);
public void handle(Callback callbacks[]) throws IOException, UnsupportedCallbackException {
log.info("进入handle()........................");
for (Callback cb: callbacks) {
if (cb instanceof NameCallback) {
NameCallback nc = (NameCallback) cb;
log.info(nc.getPrompt());
//采集用户名
String username = (new BufferedReader(new InputStreamReader(
System.in))).readLine();
nc.setName(username);
} else if(cb instanceof PasswordCallback){
PasswordCallback pc = (PasswordCallback) cb;
log.info(pc.getPrompt());
//采集用户密码
String password = (new BufferedReader(new InputStreamReader(
System.in))).readLine();
pc.setPassword(password.toCharArray());
}
}
}
}
一旦用户收集到用户账号后NameCallback,PasswordCallback对象都会存储他们,与此同时,上述login()方法会基于账号信构建UsernamePasswordPrincipal对象,并保留在登录模块中,而且login()会返回true,当login方法顺利完成用户凭证信息的收集工作后,commit会被触发,她将UsernamePasswordPrincipal对象摆到Subject对象中。
当login方法未能顺利完成用户凭证信息的收集工作后,abort会被触发,将principal等信息破换掉。当登录用户完满的完成自身的业务操作后便可以考虑退出当前的应用,调用logout方法。下面是Principal对象:
package sample;
import java.security.Principal;
/**
*
* @author worldheart
*
*/
//Acegi中的Authentication接口继承了Principal接口
public class UsernamePasswordPrincipal implements Principal {
private String username;
private String password;
//存储用户名、密码,比如marissa/koala
public UsernamePasswordPrincipal(String username, String password) {
this.username = username;
this.password = password;
}
public String getName() {
return this.username;
}
public String toString() {
return this.username + "->" + this.password;
}
}
为了使用上述登录模块,需要准备一个jaas配置文件:
Loginmodel.conf放在src下面
ScreenContent {
sample.ScreenContentLoginModule required;
};
客户应用:
package sample;
import java.io.File;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class JaasSecurityClient {
protected static final Log log = LogFactory
.getLog(JaasSecurityClient.class);
public static void main(String argv[]) throws LoginException,
SecurityException {
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为," + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
}
}
在运行客户应用之前还需要提供JVM参数,即引用到loginmoudel.conf配置文件:
-Djava.security.auth.login.config=src/loginmoudel.conf
或者通过javahome/jre/lib/security目录中的java.security配置文件指定上述loginmoudel.conf配置文件:
#login.config.url.l=file:${user.home}/.java.login.config
login.config.url.l=file:d:/eclipse/src/loginmoudel.conf
SecurityContextLoginModule是Acegi内置的一个LoginModel实现,当开发Jaas应用时,用户凭证信息的获取可能来自Acegi,此时,我们便可以采用内置的SecurityContextLoginModel。要使用SecurityContextLoginModule,我们需要在Jaas配置文件中配置它:
ACEGI {
org.acegisecurity.providers.jaas.SecurityContextLoginModule
required ignoreMissingAuthentication=true;
};
客户端应用:
package sample;
import java.io.File;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author worldheart
*
*/
public class AcegiSecurityClient {
protected static final Log log = LogFactory
.getLog(AcegiSecurityClient.class);
public static void main(String argv[]) throws LoginException, SecurityException {
LoginContext ctx = null;
//在实际企业应用中,Authentication对象的构建形式多种多样
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken("marissa", "koala"));
ctx = new LoginContext("ACEGI");
// marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为,"
// + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File(
// "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf")
// .exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
//清除已注册的SecurityContext
SecurityContextHolder.clearContext();
}
}
注意到我们并未为LoginContext提供CallbackHandler对象,由于Acegi负责提供兼容于Principal的Authentication对象,因此用户凭证的收集也不用CallbackHandler操心了。
在运行客户应用之前还需要提供JVM参数,即引用到loginmoudel.conf配置文件:
-Djava.security.auth.login.config=src/loginmoudel.conf
或者通过javahome/jre/lib/security目录中的java.security配置文件指定上述loginmoudel.conf配置文件:
#login.config.url.l=file:${user.home}/.java.login.config
login.config.url.l=file:d:/eclipse/src/loginmoudel.conf
启用Java安全管理器:大部分java开发者都知道,借助如下JVM参数能够启用java安全管理器,-Djava.security.manager。既然如此,我们通过如下JVM参数运行JaasSecurityClient客户端和AcegiSecurityClient客户端:
-Djava.security.manager -Djava.security.auth.login.config=src/loginmodule.conf
但是这样会出错:java.security.auth.login.config.AccessControlException:access denied
出错原因:默认时,直接借助“-Djava.security.manager”启动java安全管理器,JVM会采用javahome/jre/lib/security中的java.policy策略文件,而这一策略文件并未对上述涉及到的各种权限(比如:createLoginContext.ScreenContent,读取acegi.security.strategyJava属性)进行授权因此抛出了异常。
为此我们可以提供新的授权信息jaassecuritypolicy.txt策略文件。由于我们需要同LoginContext进行各类操作因此需要提供相关AuthPermission权限给Acegi
SecurityClient,同时我们使用了Commons-Logging,Log4j管理日志,因此还必须将相应的操作权限给这一客户,在操作日志的过程中,客户应用需要操控的:d:/ddlog.log日志文件因此需要将读写权限授给这一客户应用。
grant codebase "file:./-"{
permission java.io.FilePermission "D:/contactsforchapter8.log", "read, write";
permission javax.security.auth.AuthPermission "createLoginContext";
permission javax.security.auth.AuthPermission "modifyPrincipals";
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/log4j-1.2.14.jar" {
permission java.security.AllPermission;
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/commons-logging-1.0.4.jar" {
permission java.security.AllPermission;
};
实际上java的策略文件编写可以通过policytool工具。
运行JaasSecurityClient客户端应用:
-Djava.security.manager -Djava.security.policy=src/jaassecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
类似的运行AcegiSecurityClient的策略文件:
grant codebase "file:./-"{
permission java.util.PropertyPermission "acegi.security.strategy", "read";
permission java.io.FilePermission "D:/contactsforchapter8.log", "read, write";
permission javax.security.auth.AuthPermission "createLoginContext";
permission javax.security.auth.AuthPermission "modifyPrincipals";
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/log4j-1.2.14.jar" {
permission java.security.AllPermission;
};
grant codeBase
"file:D:/eclipse/workspace/contactsforchapter8/context/WEB-INF/lib/commons-logging-1.0.4.jar" {
permission java.security.AllPermission;
};
运行AcegiSecurityClient客户端应用:
-Djava.security.manager -Djava.security.policy=src/acegisecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
启用Jaas的用户授权功能:jaas的授权能力依赖java策略文件,下面提供了另一个版本的jaasSecurityClient客户应用,新增了两行java代码:
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
System.getProperty("java.io.tmpdir");
// 退出当前已登录marissa用户
ctx.logout();
此时开发者必须往jaassecuritypolicy.txt策略文件中添加如下权限到其中:
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "READ";
如果客户要求只具有marissa用户才有权利运行上述两行代码,那么应该这样:
LoginContext ctx = null;
ctx = new LoginContext("ScreenContent", new UsernamePasswordCallbackHandler());
//marissa用户登录到当前应用中
ctx.login();
log.info("当前用户已经通过用户认证");
Subject subject = ctx.getSubject();
log.info(subject);
// log.info("启用JAAS用户授权能力");
// log.info("临时目录为," + Subject.doAsPrivileged(subject, new PrivilegedAction() {
// public Object run() {
// log.info("当前用户正在经过JAAS授权操作的考验,并正调用目标业务操作");
// new File("D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf").exists();
// return System.getProperty("java.io.tmpdir");
// }
// }, null));
// 退出当前已登录marissa用户
ctx.logout();
那么jaassecuritypolicy.txt策略文件应该添加如下内容:
grant codebase "file:./-",
Principal sample.UsernamePasswordPrincipal "marissa" {
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "READ";
};
启动jaassecurityclient客户端:
-Djava.security.manager -Djava.security.policy=src/jaassecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
那么对于acegisecurityclient客户应用,acegisecuritypolicy.txt应该增加:
grant codebase "file:./-",
Principal org.acegisecurity.providers.UsernamePasswordAuthenticationToken "marissa" {
permission java.io.FilePermission "D:/eclipse/workspace/contactsforchapter8/src/loginmodule.conf", "read";
permission java.util.PropertyPermission "java.io.tmpdir", "read";
};
启动:
-Djava.security.manager -Djava.security.policy=src/acegisecuriypolicy.txt
-Djava.security.auth.login.config=src/loginmodule.conf
直击JaasAuthenticationProvider
配置:
<bean id="jaasAuthenticationProvider" class="org.acegisecurity.providers.jaas.JaasAuthenticationProvider">
<property name="authorityGranters"
<bean class="sample.TestAuthorityGranter"/>
</property>
<property name="callbackHandlers"
<list>
<bean class="org.acegisecurity.providers.jaas.JaasNameCallbackHandler"/>
<bean class="org.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/>
</property>
<property name="loginConfig" value="classpath:acegi.conf"/>
<property name="liginContextName" value="ACEGI"/>
</bean>
另外需要将JaasAuthenticationProvider添加到认证管理器:
acegi.conf的内容:
ACEGI {
sample.TestLoginModule required;
};
注释:authorityGranters属性能够为已经认证用户提供角色映射信息,由于这里的Jaas仅负责用户认证,而授权仍然被acegi接管。TestAuthorityGranter实现类:
package sample;
import java.security.Principal;
import java.util.HashSet;
import java.util.Set;
import org.acegisecurity.providers.jaas.AuthorityGranter;
/**
*
* @author worldheart
*
*/
public class TestAuthorityGranter implements AuthorityGranter {
public Set grant(Principal principal) {
Set<String> rtnSet = new HashSet<String>();
if (principal.getName().equals("TEST_PRINCIPAL")) {
rtnSet.add("ROLE_USER");
rtnSet.add("ROLE_ADMIN");
}
return rtnSet;
}
}
下面是TestLoginModel类:
package sample;
import java.security.Principal;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
/**
*
* @author worldheart
*
*/
public class TestLoginModule implements LoginModule {
private String user;
private String password;
private Subject subject;
public boolean abort() throws LoginException {
return true;
}
public boolean commit() throws LoginException {
return true;
}
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
this.subject = subject;
try {
NameCallback nameCallback = new NameCallback("prompt");
PasswordCallback passwordCallback = new PasswordCallback("prompt",
false);
callbackHandler.handle(new Callback[] {nameCallback, passwordCallback });
user = nameCallback.getName();
password = new String(passwordCallback.getPassword());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean login() throws LoginException {
if (!user.equals("marissa")) {
throw new LoginException("用户名不对");
}
if (!password.equals("koala")) {
throw new LoginException("密码不对");
}
subject.getPrincipals().add(new Principal() {
public String getName() {
return "TEST_PRINCIPAL";
}
});
subject.getPrincipals().add(new Principal() {
public String getName() {
return "NULL_PRINCIPAL";
}
});
return true;
}
public boolean logout() throws LoginException {
return true;
}
}
发表评论
-
MyEclipse生成代理方法(generate delegate methods)
2012-08-24 13:27 4326参考资料:《JAVA开发利器My+Eclipse全面详解》 ... -
ResultSet接口的absolute方法
2012-08-10 16:49 1025java.sql.ResultSet接口 boolean ab ... -
转载:单例设计模式中使用dom4j来完成(数据库配置文件)xml的解析,并完成数据库的连接
2012-08-10 15:12 1021转自:http://www.blogjava.ne ... -
.class文件批量反编译
2012-08-06 17:27 896步骤:1、下载jad.exe,并将其置于%JAVA_HOME% ...
相关推荐
- **Realm配置**:用于用户认证和授权,例如基于文件的用户数据库、JAAS集成等。 - **JNDI资源**:提供对数据库连接池、邮件服务等外部资源的访问。 通过深入研究这些版本的Tomcat,开发者不仅可以掌握服务器的基本...
【描述】"j2ee在线购物网实例源码,转载供大家共同学习"表明这是一个共享的学习资源,旨在促进开发者之间的知识交流和技能提升。通过分析和研究这个源码,开发者可以深入理解如何在实际项目中运用J2EE技术栈,包括...
内容概要:本文详细介绍了西门子S7-200SMART PLC与V20变频器通过Modbus RTU协议进行通信的具体方法和技术要点。首先阐述了硬件连接方式,强调了正确的接线和参数设置对于稳定通信的重要性。接着深入讲解了PLC程序的设计,包括Modbus主站初始化、启停控制、频率设定以及断电自恢复等功能模块的实现。此外还分享了一些实用的经验技巧,如避免通讯冲突、处理浮点数转换等问题。最后提到该方案已在实际生产环境中成功应用,表现出良好的稳定性和可靠性。 适合人群:从事自动化控制系统集成的技术人员,特别是熟悉西门子PLC和变频器产品的工程师。 使用场景及目标:适用于需要将旧型号PLC与变频器进行高效集成的企业,在不影响原有设备的基础上提升系统的智能化水平,减少人工干预,提高生产效率。 其他说明:文中提供了大量具体的编程实例和参数配置指南,有助于读者快速掌握相关技能并应用于实际工作中。同时提醒读者注意一些常见的错误及其解决方案,帮助规避潜在的风险。
内容概要:本文详细介绍了西门子PLC中用于电机控制的封装功能块,涵盖正转、反转、变频控制等多种功能。通过简化底层代码,提高编程效率和系统可靠性。文章展示了如何使用功能块实现正转、反转、变频控制、模拟量处理、故障处理等功能,并结合用户自定义数据类型(UDT)和多重背景技术,实现对大量电机的高效管理。此外,还提供了具体的代码示例,帮助读者更好地理解和应用这些功能块。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些需要频繁处理电机控制任务的人群。 使用场景及目标:适用于需要简化电机控制编程、提高系统可靠性和可维护性的工业环境。主要目标是减少重复编码的工作量,提升开发效率,确保系统稳定运行。 其他说明:文中提供的代码示例和方法不仅有助于初学者快速入门,也为有经验的工程师提供了优化现有系统的思路。通过使用这些功能块,可以在短时间内完成复杂电机控制系统的搭建和调试。
全球腐败感知数据(2000-2023)——3000行 33个指标 关于数据集 该数据集包含3000行和33列,涵盖了2000年至2023年的腐败感知指数(CPI)数据和各种治理指标。它包括国家排名、分数和其他指标,如公共部门腐败、司法腐败、贿赂指数、商业道德、民主指数、法治、政府效率、经济指标和人类发展指数。 这些数据可用于: 腐败趋势分析 腐败对GDP、人类发展指数和治理的影响 跨国比较 数据可视化和机器学习模型 该数据集对研究人员、数据分析师、政策制定者和对研究全球腐败趋势非常有用。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
内容概要:本文档详细介绍了将贝叶斯优化应用于FBCCA(滤波器组公共空间模式)参数调整的完整解决方案,包括代码实现和优化流程。首先,通过MNE库加载并预处理EEG数据,进行7-30Hz的预滤波处理,提取相关事件片段。接着,定义了FBCABayesianOptimizer类,该类包含创建动态滤波器组、获取模型参数以及定义优化目标函数的方法。其中,参数空间由离散和连续参数组成,涵盖了滤波器数量、CSP组件数、起始频率、带宽、交叠率等,并通过Optuna库进行多维搜索。优化过程中采用5折交叉验证机制,同时引入智能早停策略以提高效率。最后,提供了优化结果的可视化工具,如优化轨迹图、参数重要性图和滤波器组配置图,帮助用户更好地理解和分析优化过程。 适合人群:具有一定编程基础,尤其是对机器学习、脑电数据分析及贝叶斯优化感兴趣的科研人员和技术开发者。 使用场景及目标:①通过动态滤波器组生成算法,捕捉频段间的过渡特征;②利用混合参数空间设计,探索不同参数组合的效果;③借助高效交叉验证机制和智能早停策略,提高优化效率;④通过可视化工具,直观展示优化过程和结果。 阅读建议:此资源不仅展示了完整的代码实现,还深入探讨了FBCCA参数调整的理论基础和实际应用。建议读者在学习过程中结合理论知识与代码实践,逐步理解每个步骤的原理,并尝试调整参数以观察不同设置对优化效果的影响。同时,可根据自身硬件条件,考虑扩展建议中的GPU加速、分布式优化和在线学习等高级特性。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
街道级行政区划shp数据,wgs84坐标系,直接使用。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
电子信息工程专业毕业论文模板_基于FPGA的CRC编码器设计.pdf
鄂尔多斯市-达拉特旗-街道行政区划_150621_Shp数据-wgs84坐标系.rar
内容概要:本文详细介绍了STM32与三菱PLC FX系列整合方案,涵盖多种功能模块的实现方法及其应用场景。首先,通过寄存器级别的低层操作展示了数码管驱动、模拟量采集、定时器PWM配置等功能的具体实现方式。其次,针对定位功能进行了深入探讨,包括12轴运动控制、4路200kHz高速脉冲输出以及CAN总线扩展等高级特性。此外,文中提供了三种不同层次的代码版本供开发者选择,分别是寄存器版本、库函数版本和即将发布的HAL库版本,满足不同程度用户的开发需求。最后,强调了该方案在工业控制领域的广泛应用前景,如包装机械、立体仓库等。 适合人群:具有一定嵌入式开发经验的研发人员,尤其是对STM32和三菱PLC有研究兴趣的技术爱好者。 使用场景及目标:适用于需要将STM32与三菱PLC进行深度整合的工程项目,旨在提高工业控制系统的灵活性和功能性。具体目标包括但不限于实现高效的梯形图上传下载、在线监控、多轴运动控制、模拟量采集及CAN总线通信等功能。 其他说明:文中不仅提供了详细的代码示例和技术细节,还分享了一些实用技巧,如寄存器操作注意事项、库函数的优势以及未来HAL库版本的发展方向。对于希望深入了解STM32与三菱PLC整合方案的读者而言,是一份不可多得的学习资料。
内容概要:本文详细介绍了西门子S7-200SMART PLC与V20变频器通过Modbus RTU进行通讯的具体实施方案,涵盖硬件接线、变频器参数设置、PLC程序编写以及触摸屏配置等方面的内容。重点解决了断电自恢复的问题,确保系统在断电重启后能够自动恢复正常运行。文中还提供了多个调试技巧和常见问题解决方案,如RS485接线注意事项、波特率设置、Modbus地址映射等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉PLC和变频器应用的专业人士。 使用场景及目标:适用于需要将PLC与变频器集成的应用场合,特别是在电力供应不稳定或存在突发断电风险的环境中。目标是提高系统的稳定性和可靠性,减少人工干预,提升生产效率。 其他说明:文中提到的实际案例表明,该方案已在多个工业现场成功应用并长期稳定运行,证明了其可行性和优越性。此外,作者还分享了一些个人经验教训,帮助读者避免常见的错误和陷阱。
内容概要:本文详细介绍了基于西门子200PLC的全自动不锈钢焊接系统的程序设计及其配套的维纶触摸屏程序。项目采用了模块化设计,分为多个功能块如故障处理(FB_FaultHandling)、复位(FB_Reset)、自动模式(FB_AutoMode)和手动模式(FB_ManualMode),每个功能块职责明确,便于维护和复用。此外,还包括详细的地址分配表、电路原理图以及触摸屏界面设计,确保了系统的通用性和可维护性。文中还特别强调了故障处理模块的堆栈设计、安全回路的双冗余设计以及焊接参数的自动化计算等功能,展示了工业控制领域的最佳实践。 适合人群:从事PLC编程、工业自动化控制、机械设备维护的技术人员和工程师。 使用场景及目标:适用于需要设计和实施全自动焊接系统的工程项目,旨在提高生产效率、减少故障停机时间、优化焊接质量。通过学习本文,读者可以掌握模块化编程技巧、故障处理方法以及人机交互界面设计的最佳实践。 其他说明:本文不仅提供了具体的代码实现和电路图,还分享了许多实际调试经验和优化建议,帮助读者更好地理解和应用这些技术和方法。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
街道级行政区划shp数据,wgs84坐标系,直接下载使用。