Spring MVC系列(二):忘記密碼功能實(shí)現(xiàn)

最近為認(rèn)證系統(tǒng)添加了忘記密碼功能猛拴,使用了Spring提供的郵件API和Ehchace緩存驗(yàn)證碼羹铅。整個(gè)過(guò)程還是挺有趣,值得寫一下愉昆。

Spring郵件API

Sprin提供了一個(gè)強(qiáng)大方便的郵件API,簡(jiǎn)化了發(fā)送郵件的工作职员。可以發(fā)送富文本郵件跛溉,添加附件焊切,使用模板渲染郵件內(nèi)容。推薦看Spring實(shí)戰(zhàn)(第三版)芳室,這里只簡(jiǎn)單講一下如何發(fā)送富文本郵件专肪,其他的就不細(xì)講了。

配置郵件發(fā)送器

Spring郵件API的核心是MailSender接口堪侯,Spring自帶JavaMailSenderImpl實(shí)現(xiàn)了MailSender接口嚎尤,所以需要將JavaMailSenderImpl裝配到Bean中。

Mail.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--讀取外部屬性文件-->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:Mail.properties</value>
            </list>
        </property>
    </bean>
    <!--配置了mailSender-->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="${mail.host}" />
        <property name="port" value="${mail.port}"></property>
        <property name="username" value="${mail.username}" />
        <property name="password" value="${mail.password}" />
        <property name="defaultEncoding" value="UTF-8"></property>
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
            </props>
        </property>
    </bean>

</beans>

Mail.properties

使用QQ的郵件服務(wù)器伍宦,需要在QQ郵箱設(shè)置中開(kāi)啟STMP服務(wù)

mail.from=dai.dongliang@foxmail.com
mail.host=smtp.qq.com
mail.port=25
mail.username=675742730  
mail.password=*********
mail.smtp.auth=true  
mail.smtp.timeout=25000  

Main.Java

這只是簡(jiǎn)單的構(gòu)造了一個(gè)帶有鏈接的郵件芽死,其他更復(fù)雜的用法就不介紹了。

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext( "Mail.xml");
        JavaMailSenderImpl sender = (JavaMailSenderImpl)context.getBean("mailSender");
        //構(gòu)建郵件
        MimeMessage message=sender.createMimeMessage();
        try {
            //使用MimeMessageHelper構(gòu)建Mime類型郵件
            MimeMessageHelper helper= new MimeMessageHelper(message,true);
            helper.setFrom("dai.dongliang@foxmail.com");
            helper.setTo("xxxxxxx@foxmail.com");
            message.setSubject("Spring Mail Test");
            //第二個(gè)參數(shù)true表明信息類型是multipart類型
            helper.setText("<a href=\"http://www.magicalwolf.com\">你好</a>",true);
            sender.send(message);
        } catch (MessagingException e) {
            throw new RuntimeException("郵件構(gòu)造失敗");
        }
    }
}

至此一封郵件就發(fā)送出去了次洼,可以坐等收件人查看了关贵。

Ehcache緩存

Spring中內(nèi)置了對(duì)Ehcache的支持,封裝了EhCacheCacheManager卖毁,可以很方便的使用Ehcache揖曾。

配置CacheManager

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--配置cacheManager-->    
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
        p:cache-manager-ref="ehcache" />

    <!-- EhCache library setup -->
    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="classpath:ehcache.xml" />
</beans>

ehcache.xml

Ehcache的配置文件,這里配置一個(gè)名為CodeCache的chahe用于保存驗(yàn)證碼。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <diskStore path="java.io.tmpdir" />
    <!-- 配置自定義緩存 
        name:Cache的名稱炭剪,必須是唯一的(ehcache會(huì)把這個(gè)cache放到HashMap里)练链。 
        maxElementsInMemory:內(nèi)存中保持的對(duì)象數(shù)量。 
        maxElementsOnDisk:DiskStore中保持的對(duì)象數(shù)量念祭,默認(rèn)值為0兑宇,表示不限制。 
        eternal:是否是永恒數(shù)據(jù)粱坤,如果是隶糕,則它的超時(shí)設(shè)置會(huì)被忽略。 
        overflowToDisk:如果內(nèi)存中數(shù)據(jù)數(shù)量超過(guò)maxElementsInMemory限制站玄,是否要緩存到磁盤上枚驻。 
        timeToIdleSeconds:對(duì)象空閑時(shí)間,指對(duì)象在多長(zhǎng)時(shí)間沒(méi)有被訪問(wèn)就會(huì)失效株旷。只對(duì)eternal為false的有效再登。默認(rèn)值0,表示一直可以訪問(wèn)晾剖。 
        timeToLiveSeconds:對(duì)象存活時(shí)間锉矢,指對(duì)象從創(chuàng)建到失效所需要的時(shí)間。只對(duì)eternal為false的有效齿尽。默認(rèn)值0沽损,表示一直可以訪問(wèn)。 
        diskPersistent:是否在磁盤上持久化循头。指重啟jvm后绵估,數(shù)據(jù)是否有效。默認(rèn)為false卡骂。 
        diskExpiryThreadIntervalSeconds:對(duì)象檢測(cè)線程運(yùn)行時(shí)間間隔国裳。標(biāo)識(shí)對(duì)象狀態(tài)的線程多長(zhǎng)時(shí)間運(yùn)行一次。 
        diskSpoolBufferSizeMB:DiskStore使用的磁盤大小全跨,默認(rèn)值30MB缝左。每個(gè)cache使用各自的DiskStore。 
        memoryStoreEvictionPolicy:如果內(nèi)存中數(shù)據(jù)超過(guò)內(nèi)存限制浓若,向磁盤緩存時(shí)的策略盒使。默認(rèn)值LRU,可選FIFO七嫌、LFU。 
        -->

      <cache name="CodeCache" 
       maxElementsInMemory="10000"
       eternal="false" 
       overflowToDisk="false" 
       timeToIdleSeconds="300"
       timeToLiveSeconds="300" 
       memoryStoreEvictionPolicy="LFU" />

</ehcache>

Main.java

Ehcache的基本用法苞慢。

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext( "auth-cache.xml");
        //得到緩存管理器
        EhCacheCacheManager cacheManager = (EhCacheCacheManager)context.getBean("cacheManager");
        //得到Cache
        Cache cache = cacheManager.getCache("CodeCache");
        //存入緩存诵原,這里是驗(yàn)證碼對(duì)應(yīng)用戶名
        cache.put("123","magicwolf");
        //取出緩存
        System.out.println(cache.get("123",String.class));
        //刪除緩存
        cache.evict("123");
    }
}

忘記密碼功能

上面已經(jīng)把關(guān)鍵點(diǎn)介紹了,剩余的就是如何組織代碼,設(shè)計(jì)密碼找回流程绍赛。代碼很簡(jiǎn)單就不貼出了蔓纠。

第一步:顯示忘記密碼頁(yè)面

一個(gè)簡(jiǎn)單的表單頁(yè)面,輸入用戶名和一個(gè)60秒刷新一次的驗(yàn)證碼吗蚌。

  • 需要驗(yàn)證用戶名是否存在腿倚,郵箱是否已填寫。
  • 60秒刷新的驗(yàn)證碼防止惡意重置密碼蚯妇。
  • 60秒刷新的驗(yàn)證碼實(shí)現(xiàn)方式有很多敷燎,可以把時(shí)間信息存在session或cookie或Ehcache中。

第二步:發(fā)送郵件箩言,緩存重置密碼令牌硬贯。

  • 生成一個(gè)5分鐘內(nèi)有效的令牌,將令牌和用戶id映射保存在Ehcache中陨收。
  • 用令牌值組成重置郵件鏈接饭豹。
  • 從數(shù)據(jù)庫(kù)取出郵件地址并發(fā)送郵件。

第三步:重置密碼

  • 用戶點(diǎn)擊鏈接進(jìn)入重置密碼界面务漩。
  • 驗(yàn)證令牌值拄衰,并得到用戶Id,定位到具體用戶。
  • 用戶修改密碼饵骨。

總結(jié)

忘記密碼功能實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單翘悉,但是如何設(shè)計(jì)一個(gè)嚴(yán)密的密碼找回功能很麻煩。現(xiàn)在這個(gè)流程就很薄弱宏悦,容易受到攻擊镐确。等后面有時(shí)間了再來(lái)仔細(xì)研究一下,添加一些驗(yàn)證條件饼煞,比如密保問(wèn)題源葫,手機(jī)號(hào)驗(yàn)證這些。郵箱密碼配置文件是保存在服務(wù)器上砖瞧,明文保存會(huì)有風(fēng)險(xiǎn)息堂,建議加密保存,在通過(guò)Spring的PropertyPlaceholderConfigurer讀取加密配置块促。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荣堰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子竭翠,更是在濱河造成了極大的恐慌振坚,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斋扰,死亡現(xiàn)場(chǎng)離奇詭異渡八,居然都是意外死亡啃洋,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門屎鳍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宏娄,“玉大人,你說(shuō)我怎么就攤上這事逮壁》跫幔” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵窥淆,是天一觀的道長(zhǎng)卖宠。 經(jīng)常有香客問(wèn)我,道長(zhǎng)祖乳,這世上最難降的妖魔是什么逗堵? 我笑而不...
    開(kāi)封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮眷昆,結(jié)果婚禮上蜒秤,老公的妹妹穿的比我還像新娘。我一直安慰自己亚斋,他們只是感情好作媚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著帅刊,像睡著了一般纸泡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赖瞒,一...
    開(kāi)封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天女揭,我揣著相機(jī)與錄音,去河邊找鬼栏饮。 笑死吧兔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的袍嬉。 我是一名探鬼主播境蔼,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伺通!你這毒婦竟也來(lái)了箍土?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罐监,失蹤者是張志新(化名)和其女友劉穎吴藻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體弓柱,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沟堡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年疮鲫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弦叶。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妇多,靈堂內(nèi)的尸體忽然破棺而出伤哺,到底是詐尸還是另有隱情,我是刑警寧澤者祖,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布立莉,位于F島的核電站,受9級(jí)特大地震影響七问,放射性物質(zhì)發(fā)生泄漏蜓耻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一械巡、第九天 我趴在偏房一處隱蔽的房頂上張望刹淌。 院中可真熱鬧,春花似錦讥耗、人聲如沸有勾。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔼卡。三九已至,卻和暖如春挣磨,著一層夾襖步出監(jiān)牢的瞬間雇逞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工茁裙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塘砸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓呜达,卻偏偏與公主長(zhǎng)得像谣蠢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子查近,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理眉踱,服務(wù)發(fā)現(xiàn),斷路器霜威,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評(píng)論 6 342
  • 構(gòu)建用戶管理微服務(wù)翻譯自:https://springuni.com 構(gòu)建用戶管理微服務(wù)(一):定義領(lǐng)域模型和 R...
    極樂(lè)君閱讀 1,519評(píng)論 0 10
  • application的配置屬性谈喳。 這些屬性是否生效取決于對(duì)應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,358評(píng)論 1 27
  • 這些屬性是否生效取決于對(duì)應(yīng)的組件是否聲明為 Spring 應(yīng)用程序上下文里的 Bean(基本是自動(dòng)配置的),為一個(gè)...
    發(fā)光的魚(yú)閱讀 1,421評(píng)論 0 14