1. MD5加密

任何一个正式的企业应用中,都不会在数据库中使用明文来保存密码的,我们在之前的章节中都是为了方便起见没有对数据库中的用户密码进行加密,这在实际应用中是极为幼稚的做法。可以想象一下,只要有人进入数据库就可以看到所有人的密码,这是一件多么恐怖的事情,为此我们至少要对密码进行加密,这样即使数据库被攻破,也可以保证用户密码的安全。

最常用的方法是使用MD5算法对密码进行摘要加密,这是一种单项加密手段,无法通过加密后的结果反推回原来的密码明文。

首先我们要把数据库中原来保存的密码使用MD5进行加密:

<authentication-provider>
<password-encoder hash="md5"/>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>

启用MD5算法。用户登录时,输入的密码是明文,需要使用password-encoder将明文转换成md5形式,然后再与数据库中的已加密密码进行比对。

这些配置对普通客户不会造成任何影响,他们只需要输入自己的密码,Spring Security会自动加以演算,将生成的结果与数据库中保存的信息进行比对,以此来判断用户是否可以登陆。

这样,我们只添加了一行配置,就为系统带来了密码加密的功能。

2. 盐值加密

上面的实例在现实使用中还存在着一个不小的问题。虽然md5算法是不可逆的,但是因为它对同一个字符串计算的结果是唯一的,所以一些人可能会使用“字典攻击”的方式来攻破md5加密的系统[5]。这虽然属于暴力解密,却十分有效,因为大多数系统的用户密码都不回很长。

实际上,大多数系统都是用admin作为默认的管理员登陆密码,所以,当我们在数据库中看到“21232f297a57a5a743894a0e4a801fc3”时,就可以意识到admin用户使用的密码了。因此,md5在处理这种常用字符串时,并不怎么奏效。

为了解决这个问题,我们可以使用盐值加密“salt-source”。

修改配置文件:

<authentication-provider>
<password-encoder hash="md5">
<salt-source user-property="username"/>
</password-encoder>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>

盐值的原理非常简单,就是先把密码和盐值指定的内容合并在一起,再使用md5对合并后的内容进行演算,这样一来,就算密码是一个很常见的字符串,再加上用户名,最后算出来的md5值就没那么容易猜出来了。因为攻击者不知道盐值的值,也很难反算出密码原文。

3. 用户信息缓存

介于系统的用户信息并不会经常改变,因此使用缓存就成为了提升性能的一个非常好的选择。Spring Security内置的缓存实现是基于ehcache的,为了启用缓存功能,我们要在配置文件中添加相关的内容。

<authentication-provider>
<password-encoder hash="md5">
<salt-source user-property="username"/>
</password-encoder>
<jdbc-user-service data-source-ref="dataSource" cache-ref="userCache"/>
</authentication-provider>

我们在jdbc-user-service部分添加了对userCache的引用,它将使用这个bean作为用户权限缓存的实现。对userCache的配置如下所示:

<beans:bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
<beans:property name="cache" ref="userEhCache"/>
</beans:bean> <beans:bean id="userEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<beans:property name="cacheManager" ref="cacheManager"/>
<beans:property name="cacheName" value="userCache"/>
</beans:bean> <beans:bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>

EhCacheBasedUserCache是Spring Security内置的缓存实现,它将为jdbc-user-service提供缓存功能。它所引用的userEhCache来自spring提供的EhCacheFactoryBean和EhCacheManagerFactoryBean,对于userCache的缓存配置放在ehcache.xml中:

<ehcache>
<diskStore path="java.io.tmpdir"/> <defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/> <cache
name="userCache"
maxElementsInMemory="100"//内存中最多存放100个对象
eternal="false"//不是永久缓存
timeToIdleSeconds="600"//最大空闲时间是600s
timeToLiveSeconds="3600"//最大活动时间是3600s
overflowToDisk="true"//如果内存对象溢出则保存到磁盘
/>
</ehcache>

如果想了解有关ehcache的更多配置,可以访问它的官方网站http://ehcache.sf.net/

这样,我们就为用户权限信息设置好了缓存,当一个用户多次访问应用时,不需要每次去访问数据库了,ehcache会将对应的信息缓存起来,这将极大的提高系统的相应速度,同时也避免数据库符合过高的风险。

注意

cache-ref隐藏着一个陷阱,如果不看代码,我们也许会误认为cache-ref会在JdbcUserDetailsManager中设置对应的userCache,然后只要直接执行JdbcUserDetailsManager中的方法,就可以自动维护用户缓存。

可惜,cache-ref实际上是在JdbcUserDetailsManager的基础上,生成了一个CachingUserService,这个CachedUserDetailsService会拦截loadUserByUsername()方法,实现读取用户信息的缓存功能。我们在cache-ref中引用的UserCache实际上是放在CacheUserDetailsService中,而不是放到了原有的JdbcUserDetailsManager中,这就会导致JdbcUserDetailsManager中对用户缓存的操作全部失效。

4. 获取当前用户信息

如果只是想从页面上显示当前登陆的用户名,可以直接使用Spring Security提供的taglib。

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<div>username : <sec:authentication property="name"/></div>

如果想在程序中获得当前登陆用户对应的对象。

UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();

如果想获得当前登陆用户所拥有的所有权限。

Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) userDetails.getAuthorities();;
        

关于UserDetails是如何放到SecuirtyContext中去的,以及Spring Security所使用的TheadLocal模式,我们会在后面详细介绍。这里我们已经了解了如何获得当前登陆用户的信息。

spring security 控制用户信息用户加密 缓存用户信息的更多相关文章

  1. Spring Security——核心类简介——获得登录用户的相关信息

    核心类简介 目录 1.1     Authentication 1.2     SecurityContextHolder 1.3     AuthenticationManager和Authenti ...

  2. Spring Security控制权限

    Spring Security控制权限 1,配置过滤器 为了在项目中使用Spring Security控制权限,首先要在web.xml中配置过滤器,这样我们就可以控制对这个项目的每个请求了. < ...

  3. spring security控制session

    spring security控制session本文给你描述在spring security中如何控制http session.包括session超时.启用并发session以及其他高级安全配置. 创 ...

  4. Spring Security笔记:使用数据库进行用户认证(form login using database)

    在前一节,学习了如何自定义登录页,但是用户名.密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认证 一.项目结构 与前面的示例相比,因为 ...

  5. (二)spring Security 自定义登录页面与校验用户

    文章目录 配置 security 配置下 MVC 自定义登录页面 自定义一个登陆成功欢迎页面 效果图 小结: 使用 Spring Boot 的快速创建项目功能,勾选上本篇博客需要的功能:web,sec ...

  6. 使用Spring Security控制会话

    1.概述 在本文中,我们将说明Spring Security如何允许我们控制HTTP会话.此控件的范围从会话超时到启用并发会话和其他高级安全配置. 2.会话何时创建? 我们可以准确控制会话何时创建以及 ...

  7. 使用 spring security 中的BcryptPasswordEncoder对象对用户密码进行加密

    一.引入security启动器 在子工程中直接引入,不用指定版本号 二.在启动类中把BCryptPasswordEncoder对象注入到容器中 三.在service 层注入 四. 调用encode方法 ...

  8. Spring Security 入门(1-8)缓存EhCache

  9. spring security LDAP获取用户信息

    很多企业内部使用LDAP保存用户信息,这章我们来看一下如何从LDAP中获取Spring Security所需的用户信息. 首先在pom.xml中添加ldap所需的依赖. <dependency& ...

随机推荐

  1. 友盟消息推送UPush

    第一步:把下载的SDK里面的PushSDK当做Module导入自己的项目 第二步:在自己项目的build.gradle里面一定要配置applicationId defaultConfig { appl ...

  2. js的一些小笔记,(不定期更新)

    2个$的用法$本身并无特定意义,它表示什么意思要看是如何定义的,如果没有定义就便是两个$,可能是变量名的开始.一般是一个函数,用来代替document.getElementByIdfunction $ ...

  3. hdu1114 完全背包

    题意:给出钱罐的重量,然后是每种钱的价值和重量,问钱罐里最少可能有多少钱. 完全背包. 代码: #include<iostream> #include<cstdio> #inc ...

  4. Codeforces Round #355 (Div. 2)-B

    B. Vanya and Food Processor 题目链接:http://codeforces.com/contest/677/problem/B Vanya smashes potato in ...

  5. 《DSP using MATLAB》 示例Example4.1

    今天开始看第4章,从开始看这本书到现在,过去一个多月,收获不少,继续坚持.

  6. BZOJ 3542 [Poi2014]Couriers ——可持久化线段树

    [题目分析] 查找区间内出现次数大于一半的数字. 直接用主席树,线段树上维护区间大小,由于要求出现次数大于一半,每到一个节点可以分治下去. 时间复杂度(N+Q)logN [代码] #include & ...

  7. 关于在C#中构造函数中调用虚函数的问题

    在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...

  8. ASP.NET Global.asax详解

    最近在研究bbsmax的代码,但是一直不知道入口在哪里,然后就对各个文件分析了,然后终于在对global.asax文件查看的时候看到Application_BeginRequest才明白入口,所以现在 ...

  9. BZOJ4546(原) : 三元组

    设$f(x)=\sum_{x|d}p(d)$. 则$ans=\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n\mu(i)\mu(j)\mu(k)f(lcm(i,j))f(lcm ...

  10. IOS之同步请求、异步请求、GET请求、POST请求

    .同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作, .异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然可以 ...