1. 程式人生 > >基於SSM框架的博客系統(二)博主登錄功能

基於SSM框架的博客系統(二)博主登錄功能

erl 映射 import incr pac 加密 actor gets AC

一、 準備

1.數據庫

創建表db_blogger:

 1 DROP TABLE IF EXISTS `t_blogger`;
 2 
 3 CREATE TABLE `t_blogger` (
 4 
 5   `id` INT(11) NOT NULL AUTO_INCREMENT,
 6 
 7   `userName` VARCHAR(50) DEFAULT NULL,
 8 
 9   `password` VARCHAR(100) DEFAULT NULL,
10 
11   `profile` TEXT,
12 
13   `nickName` VARCHAR(50) DEFAULT
NULL, 14 15 `sign` VARCHAR(100) DEFAULT NULL, 16 17 `imageName` VARCHAR(100) DEFAULT NULL, 18 19 `salt` VARCHAR(100) DEFAULT NULL, 20 21 PRIMARY KEY (`id`) 22 23 ) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 24 25 INSERT INTO `t_blogger`(`id`,`userName`,`password`,`profile`,`nickName`,`sign
`,`imageName`,`salt`) VALUES (1,neya,7f50069012f25a74bb2783a2d7100f0e,NULL,NULL,NULL,NULL,Neya);

2.添加shiro支持

 1 <!-- 添加shiro支持 -->
 2 
 3      <dependency>
 4 
 5           <groupId>org.apache.shiro</groupId>
 6 
 7           <artifactId>shiro-core</artifactId>
 8
9 <version>1.2.4</version> 10 11 </dependency> 12 13 14 15 <dependency> 16 17 <groupId>org.apache.shiro</groupId> 18 19 <artifactId>shiro-web</artifactId> 20 21 <version>1.2.4</version> 22 23 </dependency> 24 25 26 27 <dependency> 28 29 <groupId>org.apache.shiro</groupId> 30 31 <artifactId>shiro-spring</artifactId> 32 33 <version>1.2.4</version> 34 35 </dependency>

二、 登錄界面及登錄控制

1. 登錄界面

在webapp文件夾下創建login.jsp,以上所需文件及圖片可由以下鏈接下載:鏈接:https://pan.baidu.com/s/1bqCGJld 密碼:701g

登錄界面如下:

技術分享圖片

2. 創建Realm並配置shiro

Shiro是一個Java平臺的開源權限框架,用於認證和訪問授權。具體來說,滿足對如下元素的支持:

1)用戶,角色,權限(僅僅是操作權限,數據權限必須與業務需求緊密結合),資源(url)。

2)用戶分配角色,角色定義權限。

3)訪問授權時支持角色或者權限,並且支持多級的權限定義。

關於shiro更詳細的信息,推薦閱讀博客:http://jinnianshilongnian.iteye.com/blog/2018398,暫時可以只閱讀前幾章,足夠本項目使用。

下面簡單說一下本項目中所用到的shiro執行流程:前端從login.jsp獲取到用戶提交的用戶名及密碼的表單數據提交到後臺的controller處理,在controller相應的登錄功能模塊中將用戶名和密碼封裝到一個token中(UsernamePasswordToken對象)。在shiro中,應用代碼直接交互的對象是Subject,也就是說shiro的對外API核心就是Subject,其代表了當前“用戶”,這個用戶不一定是具體的人,也可以是與當前應用交互的任何東西。Subject會綁定到SecurityManager,與Subject的所有交互都會委托給SecurityManager。在controller中,通過一個Subject實例通過login方法將之前創建的token提交,後續會運行到自定義的MyRealm類,在此類中由方法doGetAuthenticationInfo實現具體的驗證邏輯,首先需要根據提交的用戶名到數據庫中進行查詢,得到數據庫中相應的密碼及鹽,然後將用戶名、密碼、鹽封裝到一個info(SimpleAuthenticationInfo)中,作為方法的返回值返回,接下來的驗證由shiro進行處理,主要是對比提交的token和info中的信息,將token中的密碼取出與info中取出的鹽使用MD5加密(加密算法及次數在shiro配置文件中配置),得到加密後的字符串與info中的密碼字符串進行匹配,相同則驗證成功,否則拋出異常。

創建包com.neya.shiro,並在其中創建MyRealm類:

 1 public class MyRealm extends AuthorizingRealm{
 2 
 3  
 4 
 5      @Override
 6 
 7      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
 8 
 9  
10 
11           return null;
12 
13      }
14 
15  
16 
17      @Override
18 
19      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
20 
21           // TODO Auto-generated method stub
22 
23          
24 
25           return null;
26 
27      }
28 
29     
30 
31       public String getName(){
32 
33            return "myRealm";
34 
35       }
36 
37  
38 
39 }

在resource中創建shiro 配置文件:applicationContext-shiro:

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 
  3 <beans xmlns="http://www.springframework.org/schema/beans"
  4 
  5      xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
  6 
  7      xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  8 
  9      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 10 
 11      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 12 
 13      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
 14 
 15      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
 16 
 17      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
 18 
 19      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
 20 
 21  
 22 
 23  
 24 
 25  
 26 
 27     <!--securityManage-->
 28 
 29     <!-- 安全管理器 -->
 30 
 31      <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 32 
 33         <property name="realm" ref="customRealm" />
 34 
 35     </bean>
 36 
 37  
 38 
 39  
 40 
 41      <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
 42 
 43     
 44 
 45     <bean id="customRealm" class="com.ssm.shiro.MyRealm">
 46 
 47    
 48 
 49     <property name="credentialsMatcher">
 50 
 51                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
 52 
 53                     <!-- 加密方式 -->
 54 
 55                     <property name="hashAlgorithmName" value="MD5" />
 56 
 57                     <!-- 加密次數 -->
 58 
 59                     <property name="hashIterations" value="1"/>
 60 
 61                </bean>
 62 
 63           </property>
 64 
 65     </bean>
 66 
 67  
 68 
 69      <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
 70 
 71     <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
 72 
 73     <property name="securityManager" ref="securityManager"/>
 74 
 75 </bean>
 76 
 77  
 78 
 79  
 80 
 81 <!--web.xml中shiro的filter對應的bean-->
 82 
 83     <!-- Shiro 的Web過濾器 -->
 84 
 85     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 86 
 87        <property name="securityManager" ref="securityManager" />  
 88 
 89  <!--        loginUrl認證提交地址,如果沒有認證將會請求此地址進行認證,請求此地址將由formAuthenticationFilter進行表單認證 -->
 90 
 91         <property name="loginUrl" value="/blogger/login.do" />
 92 
 93      <!--   認證成功統一跳轉到first.do,建議不配置,不配置的話shiro認證成功會自動到上一個請求路徑 -->
 94 
 95         <property name="filterChainDefinitions">
 96 
 97             <value>
 98 
 99               
100 
101                 /login=anon
102 
103                     /admin/**=authc
104 
105                    
106 
107                     <!-- -/**=authc 表示所有的url都必須認證通過才可以訪問- -->
108 
109               
110 
111                 <!--/**=anon 表示所有的url都可以匿名訪問,anon是shiro中一個過濾器的簡寫,關於shiro中的過濾器介紹見-->
112 
113  
114 
115             </value>
116 
117         </property>
118 
119     </bean>
120 
121  
122 
123 </beans>

3. 登錄控制

使用上一篇中的逆向工程文件generatorConfig.xml將表t_blogger生成相應的實體類及mapper文件,創建相應的Service及實現類:

BloggerService.java:

1 package com.neya.service;
2 
3 import com.neya.domain.Blogger;
4 
5 public interface BloggerService {
6 
7      public Blogger getBloggerByName(String username);
8 
9 }

BloggerServiceImpl.java:

 1 package com.neya.service.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 
 5 import org.springframework.stereotype.Service;
 6 
 7 import com.neya.domain.Blogger;
 8 
 9 import com.neya.mapper.BloggerMapper;
10 
11 import com.neya.service.BloggerService;
12 
13  
14 
15 @Service
16 
17 public class BloggerServiceImp implements BloggerService {
18 
19  
20 
21      @Autowired
22 
23      private BloggerMapper bloggerMapper;
24 
25     
26 
27      @Override
28 
29      public Blogger getBloggerByName(String username) {
30 
31           // TODO Auto-generated method stub
32 
33           Blogger blogger=bloggerMapper.getByUserName(username);
34 
35           return blogger;
36 
37      }
38 
39 }

由於逆向工程自動創建的mapper中沒有getByUserName方法,所以需要在BloggerMapper.java中添加此方法並在BloggerMapper.xml中實現:

1 <select id="getByUserName" parameterType="String" resultMap="ResultMapWithBLOBs">
2 
3           select * from t_blogger where userName=#{userName}
4 
5 </select>

在MyRealm的doGetAuthenticationInfo方法中添加如下代碼:

 1 String username=(String) token.getPrincipal();
 2 
 3           Blogger blogger=bloggerService.getBloggerByName(username);
 4 
 5           if(blogger!=null){//能查詢到數據則將查詢到的數據封裝到info中與token比較
 6 
 7                SecurityUtils.getSubject().getSession().setAttribute("currentUser", blogger);
 8 
 9                ByteSource credentialsSalt = ByteSource.Util.bytes(blogger.getSalt());
10 
11                AuthenticationInfo info=new SimpleAuthenticationInfo(blogger.getUsername(), blogger.getPassword(),credentialsSalt,getName());
12 
13                return info;
14 
15           }else{
16 
17                return null;
18 
19           }

前面的login.jsp中,表單提交的地址為"${pageContext.request.contextPath}/blogger/login.do",所以在controller包中創建相應的BloggerController類並使用@RequestMapping註解映射:

package com.neya.controller;

 

import javax.servlet.http.HttpServletRequest;

 

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.subject.Subject;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

 

import com.neya.domain.Blogger;

import com.neya.service.BloggerService;

 

@Controller

@RequestMapping("/blogger")

public class BloggerController {

    

     @Autowired

     private BloggerService bloggerService;

    

     @RequestMapping("/login")

     public String login(Blogger blogger,HttpServletRequest request){//參數使用spring的自動綁定,從blogger中尋找相應的字段與前端提交的表單的‘name‘匹配,相同則會對blogger的屬性直接賦值,比如表單中提交了兩項,name屬性分別為username和password,則在blogger中,若發現有這兩個字段,則直接將提交的數據對這兩個字段賦值

          Subject subject=SecurityUtils.getSubject();

          UsernamePasswordToken token=new UsernamePasswordToken(blogger.getUsername(),blogger.getPassword());//根據前端提交的信息創建token

          try{

               subject.login(token);//登錄,這裏會執行到MyRealm中的代碼

               return "redirect:/admin/main.jsp";//登錄成功則跳轉到相應的後臺管理界面

          }catch(Exception e){//驗證失敗會拋出異常,將失敗信息寫回前端

               e.printStackTrace();

               request.setAttribute("blogger", blogger);

               request.setAttribute("errorInfo", "用戶名或密碼錯誤");

               return "login";

          }

     }

}

main.jsp及其所需要的文件在以下鏈接中:

鏈接:https://pan.baidu.com/s/1jJ9K8rO 密碼:l65t

main.jsp放在webapp下的admin文件夾中

另外,在web.xml中還需要加入shiro過濾器

 1  <!--在這裏配置shiro的filter-->
 2 
 3    <!-- shiro過慮器,DelegatingFilterProxy通過代理模式將spring容器中的bean和filter關聯起來 -->
 4 
 5     <filter>
 6 
 7        <filter-name>shiroFilter</filter-name>
 8 
 9        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
10 
11    <!--     設置true由servlet容器控制filter的生命周期 -->
12 
13        <init-param>
14 
15            <param-name>targetFilterLifecycle</param-name>
16 
17            <param-value>true</param-value>
18 
19        </init-param>
20 
21      <!--   設置spring容器filter的bean id,如果不設置則找與filter-name一致的bean -->
22 
23        <init-param>
24 
25            <param-name>targetBeanName</param-name>
26 
27            <param-value>shiroFilter</param-value>
28 
29        </init-param>
30 
31    </filter>
32 
33    <filter-mapping>
34 
35        <filter-name>shiroFilter</filter-name>
36 
37        <url-pattern>/*</url-pattern>
38 
39    </filter-mapping>

接下來啟動tomcat,並在瀏覽器中輸入http://localhost:8080/MyBlog/login.jsp,填入用戶名neya及密碼123456,點擊登錄即可跳轉到相應後臺管理界面

基於SSM框架的博客系統(二)博主登錄功能