spring-security番外篇

1、spring-security maven地址

<!-- Spring Security -->
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-core</artifactId>
         <version>3.1.4.RELEASE</version>
     </dependency>
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-web</artifactId>
         <version>3.1.4.RELEASE</version>
     </dependency>
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-config</artifactId>
         <version>3.1.4.RELEASE</version>
     </dependency>
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-taglibs</artifactId>
         <version>3.1.4.RELEASE</version>
     </dependency>

2、加密

Public interface PasswordEncoder{  
  String encode(String rawPassword);  
  Boolean matches(String rawPassword,String encodedPassword);  
} 

定义了两个方法,encode方法是对方法加密,而match方法是用来验证密码和加密后密码是否一致的,如果一致则返回true。和authentication.encoding包中的PasswordEncoder接口相比,简化了许多。

位于org.springframeword.security.crypto.password包中的
StandardPasswordEncoder类,是PasswordEncoder接口的(唯一)一个实现类,是本文所述加密方法的核心。它采用SHA-256算法,迭代1024次,使用一个密钥(site-wide secret)以及8位随机盐对原密码进行加密。
随机盐确保相同的密码使用多次时,产生的哈希都不同; 密钥应该与密码区别开来存放,加密时使用一个密钥即可;对hash算法迭代执行1024次增强了安全性,使暴力破解变得更困难些。

和上一个版本的PasswordEncoder比较,好处显而易见:盐值不用用户提供,每次随机生成;多重加密————迭代SHA算法+密钥+随机盐来对密码加密,大大增加密码破解难度。

import org.springframework.security.crypto.password.PasswordEncoder;  
import org.springframework.security.crypto.password.StandardPasswordEncoder;  

/** 
 * @author XUYI 
 * Spring Security 3.1 PasswordEncoder 
 */  
public class EncryptUtil {  
    //从配置文件中获得  
    private static final String SITE_WIDE_SECRET = "my-secret-key";  
    private static final PasswordEncoder encoder = new StandardPasswordEncoder(  
       SITE_WIDE_SECRET);  

    public static String encrypt(String rawPassword) {  
         return encoder.encode(rawPassword);  
    }

    public static boolean match(String rawPassword, String password) {  
         return encoder.matches(rawPassword, password);  
    }

    public static void main(String[] args) {  
        System.out.println(EncryptUtil.encrypt("每次结果都不一样伐?"));  
        System.out.println(EncryptUtil.encrypt("每次结果都不一样伐?"));  
        System.out.println(EncryptUtil.encrypt("每次结果都不一样伐?"));  
        System.out.println(EncryptUtil.encrypt("每次结果都不一样伐?"));  
        System.out.println(EncryptUtil.encrypt("每次结果都不一样伐?"));
    }
 }

1用户验证–转

1.  首先CustomUserDetailsService需要实现UserDetailsService(org.springframework.security.core.userdetails.UserDetailsService)接口, 实现获取用户Detail信息的回调函数. 必须要实现的方法是loadUserByUsername
注意: 这里的user类必须继承userDetail类, 并且必须继承
  private  String password;
  private  String username;
  private  Set<GrantedAuthority> authorities;
  private  boolean accountNonExpired;
  private  boolean accountNonLocked;
private  boolean credentialsNonExpired;
这五个属性
和hashCode, equals这两个方法;
构造方法中必须给上述的5个属性赋值, CustomUserDetailsService调用构造方法, 生成一个user对象;
如果user不存在, 这里可以直接抛出UsernameNotFoundException异常, 具体流程自己试验下, 前台SPRING_SECURITY_LAST_EXCEPTION显示的错误是:”坏的凭证”

2.  loadUserByUsername方法返回后会跳到DaoAuthenticationProvider(org.springframework.security.authentication.dao.DaoAuthenticationProvider)类中retrieveUser方法中
3.  retrieveUser方法返回后会跳到
AbstractUserDetailsAuthenticationProvider(org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider) authenticate方法中,这个方法会先到缓存中查找user:
String username =(authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
 如果没有的话会从上一步DaoAuthenticationProvider的loadUserByUsername方法把user查出来。这里会抛UsernameNotFoundException这个异常, 应该是用户不存在这个错误, 即Bad credentials.
4. authenticate方法里面
preAuthenticationChecks.check(user);这里进行基本有效性验证(是否有效, 是否被锁, 是否过期); 代码如下:
if (!user.isAccountNonLocked()) {
                throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
                        "User account is locked"), user);
            }

            if (!user.isEnabled()) {
                throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
                        "User is disabled"), user);
            }

            if (!user.isAccountNonExpired()) {
                throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
                        "User account has expired"), user);
            }


5.  authenticate方法里面
additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);这里进行密码验证.

additionalAuthenticationChecks调用的是DaoAuthenticationProvider(org.springframework.security.authentication.dao.DaoAuthenticationProvider)中的additionalAuthenticationChecks的方法; 应该是继承的关系;
具体比较的方法写在 Md4PasswordEncoder(org.springframework.security.authentication.encoding.Md5PasswordEncoder)类中的
 public boolean isPasswordValid(String encPass, String rawPass, Object salt) 方法中; 可是debug中中不到
Md5PasswordEncoder实现的isPasswordValid方法; 这很蹊跷...不过根据配置文件中; 加密方式应该是md5;
<!-- 用户的密码加密或解密 -->
    <bean id="passwordEncoder"
        class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />

<!-- 注意能够为authentication-manager 设置alias别名  -->
    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="userDetailsManager">
            <password-encoder ref="passwordEncoder">
                <salt-source user-property="username" />
            </password-encoder>
        </authentication-provider>
    </authentication-manager>
所以应该Md5PasswordEncoder也有实现isPasswordValid(String encPass, String rawPass, Object salt) 这个方法; 

至于前台password怎么传到这里; spring security拦截了j_spring_security_check请求; 并把j_password赋给了DaoAuthenticationProvider(org.springframework.security.authentication.dao.DaoAuthenticationProvider)中passwordEncoder属性; 这个还没验证过;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值