shiro MD5盐值加密

shiro加密流程:
这里写图片描述

——————————————————————————————————–图片仅供参考!


我是用的shiro与SSM整合:

首先是shiro配置文件:

<!-- 配置进行授权和认证的 Realm,要新增一个java类来实现,下面会有,class=包名.类名 -->
    <bean id="myRealm" class="shiro.MyRealm">
         <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"></property> <!-- 加密算法的名称 -->
                <property name="hashIterations" value="1024"></property> <!-- 配置加密的次数 -->
            </bean>
        </property>
    </bean>

注册的controller:


/**
 * 用于注册普通用户,以便登录
 * @author Young
 *
 */
@Controller
public class RegisterController {

    private UserServiceI userService;

    public UserServiceI getUserService() {
        return userService;
    }

    @Autowired
    public void setUserService(UserServiceI userService) {
        this.userService = userService;
    }
/**
 * 使用md5盐值加密用于注册用户信息,盐即为用户Id;用户id与用户名相同
 * @param user
 * @return
 */
    @RequestMapping(value = "registerUser",method = RequestMethod.POST)
    public String registerUser(Sys_user user){
        //加密密码
        String password = new SimpleHash("MD5", user.getPassword(), user.getUserName(), 1024).toString();
        user.setPassword(password);
        userService.AddSys_User(user);
        return "/jsp/user/registerSuccess";
    }
}

userService.AddSys_User(user);将用户插入数据库;

登录的controller:

/**
     * 登陆控制
     * @return
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String login(HttpServletRequest request,String userName,String password) {

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
        try{
            //调用subject.login(token)进行登录,会自动委托给securityManager,调用之前  
            subject.login(token);//会跳到我们自定义的realm中 
            return "/jsp/index/index";
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("用户名或密码错误");
            //request.setAttribute("error", "用户名或密码错误");
            return "/jsp/login/loginError";
        }
    }

自定义realm中进行登录认证

    /**
     * 用于登录认证,匹配数据库的信息.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        String userName = (String) token.getPrincipal();// 获取用户名

        // 根据用户输入的用户名在数据库进行匹配
        Sys_user user = userService.getUserByName(userName);
        //用户名存在则匹配密码
        if (user != null) {
             //1)principal:认证的实体信息,可以是userName,也可以是数据库表对应的用户的实体对象  
            Object principal = user.getUserName();

            //2)credentials:数据库中的密码  
            Object credentials = user.getPassword(); 

            //3)realmName:当前realm对象的name,调用父类的getName()方法即可  
            String realmName = getName();  

            //4)credentialsSalt盐值  
            ByteSource credentialsSalt = ByteSource.Util.bytes(userName);//使用用户名作为盐值  

            //根据用户的情况,来构建AuthenticationInfo对象,通常使用的实现类为SimpleAuthenticationInfo
            //5)与数据库中用户名和密码进行比对,密码盐值加密,第4个参数传入realName。
            SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(principal, credentials,credentialsSalt,realmName);
            return authcInfo;
        } else {
            return null;
        }
    }

通过用户的唯一标识得到 AuthenticationInfo 然后和 AuthenticationToken (用户名 密码)

部分源码如下:

 /**
     * Asserts that the submitted {@code AuthenticationToken}'s credentials match the stored account
     * {@code AuthenticationInfo}'s credentials, and if not, throws an {@link AuthenticationException}.
     *
     * @param token the submitted authentication token
     * @param info  the AuthenticationInfo corresponding to the given {@code token}
     * @throws AuthenticationException if the token's credentials do not match the stored account credentials.
     */
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
            if (!cm.doCredentialsMatch(token, info)) {
                //not successful - throw an exception to indicate this:
                String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                throw new IncorrectCredentialsException(msg);
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                    "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                    "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }
    }

具体的比较在doCredentialsMatch中实现;

这里写图片描述

具体的源码大佬们自己去看看,我还看不懂!

如果token与info的信息匹配的话,则登录成功!

此外就是为什么要盐值加密

因为可能存在多个用户的注册的密码时相同的,所以在密码hash过程中添加额外的随机值,即加盐

由上面可以看出来我的盐值就是每个用户的用户Id,
SimpleHash参数为:加密算法名,加密源,盐,迭代次数
SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)

        //加密密码
        String password = new SimpleHash("MD5", user.getPassword(), user.getUserName(), 1024).toString();

猜你喜欢

转载自blog.csdn.net/young_fee/article/details/79954477