天天看点

spring security 粗识

最近才开始接触spring security来开发项目,把里面觉得不太懂的或者有意思的现在大概总结一下,方便以后自己再看,再学习...

①LDAP(轻目录访问协议),看了看,不是特别懂,在此就不献丑了,想深入了解还是度娘。

②sitemesh技术的应用,装饰类的配置文件decorators.xml,主要的

<!-- 要进行装饰的页面-->

<decorator name="main" page="main.jsp">

  <pattern>/*</pattern>

 </decorator>

<!-- 不需要被装饰的页面 -->

<excludes>

  <pattern>/login.jsp*</pattern>

 </excludes>

③关于spring security 3.1登陆验证,我从这里面受益匪浅 http://blog.csdn.net/k10509806/article/details/6436987 ,登陆这块流程还算是比较详细的。

④密码的一些规则:

* At least 8 characters.

至少8个字符

* A minimum of one numeric character.

至少包含一个数字字符

* A minimum of one special character (e.g., @, #, $).

至少包含一个特殊字符 (如, @,#,$)

* A leading and ending alpha character.

以字母为开头且以字母结束

* contain at least one uppercase letter

密码至少需要包含一个大写字母。

* Be unique to the previous 13 passwords.

修改的密码不能与前13次密码重复

* Be restricted to one change(s) within a 24 hour period except for one-time-password implementations.

除一次性使用密码外,24小时内限制只能改一次密码

* Not be programmed into "remember password" features, scripts or function keys.

不能把”记住密码“功能编码在程序的功能模块或脚本里

* User account passwords must be changed every 90 days.

用户帐号密码必须每90天修改一次

* Maximum number of 5 consecutive failed login attempts, after which the user's access must be suspended.

在最多连续5次尝试登录失败后用户必须被挂起

* Store and transmit passwords in protected (e.g., encrypted or hashed) form.

存储和发送密码要以加密的方式进行

? The storage, display, and printing of passwords must be masked, suppressed, or otherwise obscured

密码不能以明文存储,显示和打印

⑤加密算法

自带的加密算法:

private MessageDigestPasswordEncoder passwordEncoder;

public void setPasswordEncoder(MessageDigestPasswordEncoder passwordEncoder) {

  this.passwordEncoder = passwordEncoder;

}

passwordRecord.setPassword(passwordEncoder.encodePassword(password,null));

自写加密算法:

public class DefaultDESedeImpl implements StringEncryptor {

  //加密

 public String encrypt(String target) {

  String encodeString = null;

  encodeString = new BASE64Encoder().encode(target.getBytes());

  return encodeString;

 }

  //解密

 public String decrypt(String target) {

  String decodeString = null;

  try {

   decodeString = new String(new BASE64Decoder().decodeBuffer(target));

  } catch (IOException e) {

   e.printStackTrace();

  }

  return decodeString;

 }

}

⑥用户登陆判断的思路(这里面用户被锁,是必须要超级用户来解锁)

0.判断该用户是否已经被挂起,如果被挂起,就不执行。。。

1.根据用户名去数据库user表查,没有 返回空,不执行操作,有的话

==>  判断该用户是否被锁,如果被锁,返回,没有被锁,判断loginservice是否有数据,没有数据,直接创建,有数据的话--

2.去loginRecord(登陆记录)表中查相对应的username,如果为空,则直接插入,username,failure_times=1,date = new Date();

3.不为空返回对应的failure_times和date,failure_times如果为0,failure_times=1,date= new Date();

4.如果failure_times不为空但是new Date>date+5分钟(5分钟内连续操作);,failure_times=1,date= new Date();

5.如果new Date<date+5分钟;failure_times=failure_times+1;将之前取出的时间放入数据库

6.登陆成功{

  将loginRecord表中该用户名的failure_times清零。

 }

 ==>解锁的时候应该将loginRecord里面的对应的用户failure_times清零.

⑦取WEB-INF下面的properties里面的内容

public class AppConfigUtil {

 public Properties properties;

 public String fileName = "config.properties";

 public AppConfigUtil() {

  try {

   properties = new Properties();

   String path = this.getClass().getResource("/").getPath();

   path = path.substring(1,path.indexOf("classes"));

   properties.load(new FileInputStream(path+"app-config.properties"));

  } catch (Exception e) {

   e.printStackTrace();

  }

 }

 //

 public String getValue(String confName) {

  if (StringUtils.isEmpty(confName)) {

   return "";

  } else {

   return properties.getProperty(confName);

  }

 }

 public void setProperties(Properties properties) {

  this.properties = properties;

 }

 public String getFileName() {

  return fileName;

 }

 public void setFileName(String fileName) {

  this.fileName = fileName;

 }

这个在测试的时候是可以用的,但是服务器启动起来,路径就会出错,所以,在服务器端,如果可以的话,再把request对象传入,这样就能取得服务器端的地址:

public class AppConfigUtil {

 public Properties properties;

 public AppConfigUtil(HttpServletRequest request) {

  try {

   String filePath = request.getRealPath("/WEB-INF/config.properties");

   properties = new Properties();

   InputStream in = new BufferedInputStream(new FileInputStream(filePath));

   properties.load(in);

  } catch (Exception e) {

   e.printStackTrace();

  }

 }

 public String getValue(String confName) {

  if (StringUtils.isEmpty(confName)) {

   return "";

  } else {

   return properties.getProperty(confName);

  }

 }

 public void setProperties(Properties properties) {

  this.properties = properties;

 }

}

⑧自己对登陆这一块的认识:

login.jsp

<form action="<core:url value="/j_spring_security_check"/>" method="post">

<input name="j_username" type="text" style="width:130px;border:1px solid #9D9D9D"/>

<input name="j_password" type="password" style="width:130px;border:1px solid #9D9D9D"/>

固定的j_username和j_password 通过固定的action传入/j_spring_security_check,到下面进行判断

applicationContext-security.xml

<bean id="securityFilter"

  class="com.xxx.util.LocaleSaverAuthenticationProcessingFilter">

  <property name="authenticationManager" ref="authenticationManager" />

  <property name="authenticationSuccessHandler" ref="successHandler" />

  <property name="authenticationFailureHandler" ref="failureHandler" />

  <property name="filterProcessesUrl" value="/j_spring_security_check" />

 </bean>

<bean id="successHandler"

  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">

  <property name="defaultTargetUrl" value="/home.htm" />

 </bean>

 <bean id="failureHandler"

  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">

  <property name="defaultFailureUrl" value="/login.jsp?authfailed=Y" />

 </bean>

<bean id="loginService" class="com.xxx.service.login.LoginService">

  <property name="loginRecordService" ref="loginRecordService"></property>

  <constructor-arg index="0" ref="userService" />(有构造方法这样写)

   </bean>

 <security:authentication-manager alias="authenticationManager">

  <security:authentication-provider

   user-service-ref="loginService">

   <security:password-encoder ref="passwordEncoder" />

  </security:authentication-provider>

 </security:authentication-manager>

进入这里面后,会执行LocaleSaverAuthenticationProcessingFilter的attemptAuthentication方法

Authentication auth = super.attemptAuthentication(request, response);//执行这句的时候会去调用loginService的loadUserByUsername方法(记得里面调用的其他service的set,get方法,下面的是不完全代码,只是一个思路)

public class LoginService implements UserDetailsService,Serializable {

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException{

user = userService.getUserByName(userName);

if (user == null)

   throw new UsernameNotFoundException(userName + " cannot be found!");

}

return new LoginUser(user,  sourceSystemID);

}

public class LoginUser implements UserDetails {

private User user;

private Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

}

根据返回的结果,来进行下一步操作,如果成功,if (auth.isAuthenticated()) {...}return auth;

否则的话,会返回相对应的错误信息,如刚才写的抛出新的异常,就是页面显示的信息,具体的方案还是参考上面。

先写到这里保存一下,后续再继续更新修改一下。。。