JAVA實現用戶的權限管理


 

一:權限管理簡介

    做系統時肯定遇到最常見的就是不同的用戶的需求是不一樣的,就拿登陸來說,一個辦公管理系統,不同部門的人肯定要求的功能和權限都是不一樣的,那你不可能對每一個部門都寫一個登陸頁面,給不同的url吧!亦或者在下邊選擇你是什么部門的人?那每個部門內還有等級吶!再繼續選?然后給每個人寫一個界面?那明顯是不可能的,那我們到底要怎么實現吶?

    最常用的方法就是划分不同的角色,賦予角色權限,然后再讓用戶去申請角色就好了,具體的實現慢慢說。

二:數據表的設計

根據角色授權的思想,我們需要涉及五張表(簡單一寫,沒寫約束,湊活看吧)

1)三張主表

a)用戶表(user)

b) 角色表(role)

c) 資源表(module)[你也可以叫他權限表等等,反正就是代表着各種權限]

2)兩張中間表

d)用戶角色表(user_role)

e)角色資源表(permission)

 1 CREATE TABLE `user` (
 2   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
 3   `username` varchar(32) DEFAULT NULL COMMENT '用戶名',
 4   `password` varchar(32) DEFAULT NULL COMMENT '密碼',
 5   PRIMARY KEY (`id`)
 6 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';
 7 
 8 CREATE TABLE `role` (
 9   `id` int(11) NOT NULL AUTO_INCREMENT,
10   `name` varchar(32) DEFAULT NULL COMMENT '角色名',
11   `desc` varchar(32) DEFAULT NULL COMMENT '角色描述',
12   PRIMARY KEY (`id`)
13 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
14 
15 CREATE TABLE `resource` (
16   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
17   `title` varchar(32) DEFAULT NULL COMMENT '資源標題',
18   `uri` varchar(32) DEFAULT NULL COMMENT '資源uri  ',
19   PRIMARY KEY (`id`)
20 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='資源表';
21 
22 CREATE TABLE `user_role` (
23   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
24   `user_id` int(11) NOT NULL COMMENT '用戶id',
25   `role_id` int(11) NOT NULL COMMENT '角色id',
26   PRIMARY KEY (`id`)
27 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶角色表';
28 
29 CREATE TABLE `role_resource` (
30   `id` int(11) NOT NULL AUTO_INCREMENT,
31   `role_id` int(11) DEFAULT NULL COMMENT '角色id',
32   `resource_id` int(11) DEFAULT NULL COMMENT '資源id',
33   PRIMARY KEY (`id`)
34 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色資源表';
db.sql

三:使用Shiro整合Spring進行管理權限

1:Shiro簡介

  Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。使用Shiro的易於理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。

  Shiro 主要分為來個部分就是認證和授權,在個人感覺來看就是查詢數據庫做相應的判斷而已。Shiro的主要框架圖如下

是不是看到這張圖,有點不想看了,有些混亂有些多,我就其中一些方法進行簡要說明

1:Subject

  Subject即主體,外部應用與subject進行交互,subject記錄了當前操作用戶,將用戶的概念理解為當前操作的主體,可能是一個通過瀏覽器請求的用戶,也可能是一個運行的程序。 Subject在shiro中是一個接口,接口中定義了很多認證授相關的方法,外部程序通過subject進行認證授,而subject是通過SecurityManager安全管理器進行認證授權。

2:SecurityManager

  SecurityManager即安全管理器,對全部的subject進行安全管理,它是shiro的核心,負責對所有的subject進行安全管理。通過SecurityManager可以完成subject的認證、授權等,實質上SecurityManager是通過Authenticator進行認證,通過Authorizer進行授權,通過SessionManager進行會話管理等。

3:Authorizer

  Authorizer即授權器,用戶通過認證器認證通過,在訪問功能時需要通過授權器判斷用戶是否有此功能的操作權限。

4:Realm

  Realm即領域,相當於datasource數據源,securityManager進行安全認證需要通過Realm獲取用戶權限數據,比如:如果用戶身份數據在數據庫那么realm就需要從數據庫獲取用戶身份信息。

5:sessionManager

  sessionManager即會話管理,shiro框架定義了一套會話管理,它不依賴web容器的session,所以shiro可以使用在非web應用上,也可以將分布式應用的會話集中在一點管理,此特性可使它實現單點登錄。

6:SessionDAO

  SessionDAO即會話dao,是對session會話操作的一套接口,比如要將session存儲到數據庫,可以通過jdbc將會話存儲到數據庫。

7:CacheManager

  CacheManager即緩存管理,將用戶權限數據存儲在緩存,這樣可以提高性能。

8:Cryptography

  Cryptography即密碼管理,shiro提供了一套加密/解密的組件,方便開發。比如提供常用的散列、加/解密等功能。

2:Shiro認證過程

1):引入shiro的jar包

1 <dependency>
2      <groupId>org.apache.shiro</groupId>
3      <artifactId>shiro-core</artifactId>
4      <version>1.4.0</version>
5 </dependency>
shiro坐標

2):創建類文件

  2.1構建SecurityManager環境

1 DefaultSecurityManager defaultSecurityManager = new DefaultSecrityManager();
2 
3 defaultSecurityManager.setRealm(simpleAccountRealm);
View Code

 

2.2主體提交認證請求

 1 SecurityUtils.setSecurityManager(defaultSecurityManager);
 2 
 3 Subject subject = SecurityUtils.getSubject();
 4 
 5 UsernamePasswordToKen token = new UsernamePassword(username : "小明",password :“123456”):
 6 
 7 subject.login(token);
 8 
 9 system.out.println("isAuthenticated:" + subject.isAuthenticated());
10 
11 subject.logout();
12 
13 system.out.println("isAuthenticated:" + subject.isAuthenticated());
提交認證

2:Shiro授權過程

 

1)類文件

1.1構建SecurityManager環境

1 DefaultSecurityManager defaultSecurityManager = new DefaultSecrityManager();
2 
3 defaultSecurityManager.setRealm(simpleAccountRealm);
環境

 

1.2主體提交認證請求

 1 SecurityUtils.setSecurityManager(defaultSecurityManager);
 2 
 3 Subject subject = SecurityUtils.getSubject();
 4 
 5 UsernamePasswordToKen token = new UsernamePassword(username : "小明",password :“123456”):
 6 
 7 subject.login(token);
 8 
 9 system.out.println("isAuthenticated:" + subject.isAuthenticated());
10
11 subject.checkRole(s:"admin");
12 
13 subject.checkRoles(...string:"admin","user");
14 
15 subject.logout();
16 
17 system.out.println("isAuthenticated:" + subject.isAuthenticated());
提交認證

3:關於Realm

Realm一般有三種,分別是,一般都使用自定義

1)IniRealm控制   .Ini 文件。

2)jdbcRealm控制 數據庫文件

引入Mysql驅動包,引入數據源文件,設置jdbcurl以及用戶名和密碼

1 JdbcRealm.jdbcRealm = new JdbcRealm();
2 
3 jdbcRealm.setDataSource(dataSource);
4 
5 jdbcRealm.setPermisssionsLookupEnabled(true);
View Code

主體提交驗證

1 subject.checkRole(s:"admin");
2 
3 subject.checkRoles(...string:"admin","user");
4 
5 subject.checkPermission(s:"user:select");
驗證

3)自定義realm

 1 package com.fuwh.realm;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 import org.apache.shiro.authc.AuthenticationException;
 9 import org.apache.shiro.authc.AuthenticationInfo;
10 import org.apache.shiro.authc.AuthenticationToken;
11 import org.apache.shiro.authc.SimpleAuthenticationInfo;
12 import org.apache.shiro.authz.AuthorizationInfo;
13 import org.apache.shiro.realm.AuthorizingRealm;
14 import org.apache.shiro.subject.PrincipalCollection;
15 
16 import com.fuwh.util.DbUtil;
17 
18 public class MyJdbcRealm extends AuthorizingRealm{
19 
20     @Override
21     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
22         // TODO Auto-generated method stub
23         return null;
24     }
25 
26     @Override
27     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
28         // TODO Auto-generated method stub
29         Connection conn=DbUtil.getConnection();
30         String sql="select * from members2 where username=?";
31         try {
32             PreparedStatement ps=conn.prepareStatement(sql);
33             ps.setString(1, token.getPrincipal().toString());
34             ResultSet rs=ps.executeQuery();
35             while(rs.next()) {
36                 AuthenticationInfo info=new SimpleAuthenticationInfo(rs.getString("username"),rs.getString("password"),"salt");
37                 return info;
38             }
39         } catch (SQLException e) {
40             // TODO Auto-generated catch block
41             e.printStackTrace();
42         }
43         
44         return null;
45     }
46     
47 }
MyJdbcRealm 

4:關於md5加密

  4.1環境搭建及使用

 1 CustomRealm customRealm = new CustomRealm();
 2 
 3 //1.構建SecurityManager 環境
 4 
 5 DefaultSecurityManager defaultSecurityManager = new DefaultSecrityManager();
 6 
 7 defalultSecurityManager.setRealm(customRealm);
 8 
 9 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
10 
11 matcher.setHashAlgorithmName("md5");
12 
13 matcher.setHashIterations(1);
14 
15 customRealm.setCredentialsMatcher(matcher);
16 
17 //2.主體提交認證請求
18 
19 SecurityUtils.setSecurityManager(defaultSecurityManager);
20 
21 Subject subject = SecurityUtils.getSubject();
22 
23 UsernamePasswordToken token = new UsernamePassowrdToken(username:"xiaoming",password:"123456");
24 
25 subject.login(token);
26 
27 System.out.println("isAuthenticated:" + subject.isAuthenticated())
main

4.2 MD5加密

 1 @Override
 2 
 3 protected AuthenticationInfo doGetAuthenticationInfo(AuthticationToken authenticationToken) throws AuthenticationRxception {
 4 
 5 //1.從主體傳過來的認證信息中,獲取用戶名
 6 
 7 String userName = (String)authenticationToken.getPrincipal();
 8 
 9 //2.通過用戶名到數據庫獲取憑證
10 
11 String password = getPasswordByUserName(userName);
12 
13 if(password == null){
14 
15   return null;
16 
17 }
18 
19 SimpleAuthenticationInfo authticationInfo = new SimpleAuthenticationInfo (principal:“xiaoming”,password,realmName:"customRealm");
20 
21 authenticationInfo.setCredentialsSaltSalt(ByteSource.Util.bytes(string:"XQC"));
22 
23 return authenticationInfo;
24 
25 }  
加密

 

 四:Shiro在Web項目中的使用

  實戰中shiro的應用很多,幾乎都要用到,這里舉一個Blog的登陸的例子,更好的理解和使用。本博客是采用spring+springMVC+Mybatis實現的。

  1:執行流程

2:登錄頁面 login.jsp

 1 <!--只截取form表單部分-->
 2 <form action="${pageContext.request.contextPath}/blogger/login.do" method="post" onsubmit="return checkForm()">
 3     <DIV style="background: rgb(255, 255, 255); margin: -100px auto auto; border: 1px solid rgb(231, 231, 231); border-image: none; width: 400px; height: 200px; text-align: center;">
 4         <DIV style="width: 165px; height: 96px; position: absolute;">
 5             <DIV class="tou">
 6             </DIV>
 7             <DIV class="initial_left_hand" id="left_hand">
 8             </DIV>
 9             <DIV class="initial_right_hand" id="right_hand">
10             </DIV>
11         </DIV>
12         <P style="padding: 30px 0px 10px; position: relative;">
13             <SPAN class="u_logo"></SPAN>
14             <INPUT id="userName" name="userName" class="ipt" type="text" placeholder="請輸入用戶名" value="${blogger.userName }"> 
15         </P>
16         <P style="position: relative;">
17             <SPAN class="p_logo"></SPAN>         
18             <INPUT id="password" name="password" class="ipt"  type="password" placeholder="請輸入密碼" value="${blogger.password }">   
19           </P>
20         <DIV style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;">
21             <P style="margin: 0px 35px 20px 45px;">
23             <span><font color="red" id="error">${errorInfo }</font></span>
24             <SPAN style="float: right;"> 
25                   <input type="submit" style="background: rgb(0, 142, 173); padding: 7px 10px; border-radius: 4px; border: 1px solid rgb(26, 117, 152); border-image: none; color: rgb(255, 255, 255); font-weight: bold;" value="登錄"/> 
26              </SPAN>         
27              </P>
28         </DIV>
29     </DIV>
30 </form>

3:Controller層的控制

 1 package com.xqc.controller;
 2 
 3 /**
 4  * 博主Controller層
 5  *
 6  */
 7 @Controller
 8 @RequestMapping("/blogger")
 9 public class BloggerController {
10 
11     @Resource
12     private BloggerService bloggerService;
13     
14     /**
15      * 用戶登錄
16      * @param blogger
17      * @param request
18      * @return
19      */
20     @RequestMapping("/login")
21     public String login(Blogger blogger,HttpServletRequest request){
22         Subject subject=SecurityUtils.getSubject();
23         UsernamePasswordToken token=new UsernamePasswordToken(blogger.getUserName(), CryptographyUtil.md5(blogger.getPassword(), "xqc"));
24         try{
25             subject.login(token); // 登錄驗證
26             return "redirect:/admin/main.jsp";
27         }catch(Exception e){
28             e.printStackTrace();
29             request.setAttribute("blogger", blogger);
30             request.setAttribute("errorInfo", "用戶名或密碼錯誤!");
31             return "login";
32         }
33     }
34     
35 
36 }

4:在spring的配置文件中添加shiro的過濾器

 1     <!-- Shiro過濾器 -->
 2     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
 3         <!-- Shiro的核心安全接口,這個屬性是必須的 -->  
 4         <property name="securityManager" ref="securityManager"/>
 5         <!-- 身份認證失敗,則跳轉到登錄頁面的配置 -->  
 6         <property name="loginUrl" value="/login.jsp"/> 
 7         <!-- Shiro連接約束配置,即過濾鏈的定義 -->  
 8         <property name="filterChainDefinitions">  
 9             <value>
10                 /login=anon
11                 /admin/**=authc
12             </value>  
13         </property>
14     </bean>  
15     

5:攔截后交給自定義Realm進行驗證。

 1 package com.xqc.realm;
 2 
 3 import javax.annotation.Resource;
 4 
 5 
 6 import org.apache.shiro.SecurityUtils;
 7 import org.apache.shiro.authc.AuthenticationException;
 8 import org.apache.shiro.authc.AuthenticationInfo;
 9 import org.apache.shiro.authc.AuthenticationToken;
10 import org.apache.shiro.authc.SimpleAuthenticationInfo;
11 import org.apache.shiro.authz.AuthorizationInfo;
12 import org.apache.shiro.realm.AuthorizingRealm;
13 import org.apache.shiro.subject.PrincipalCollection;
14 
15 import com.xqc.entity.Blogger;
16 import com.xqc.service.BloggerService;
17 
18 /**
19  * 自定義Realm
20  *
21  */
22 public class MyRealm extends AuthorizingRealm{
23 
24     @Resource
25     private BloggerService bloggerService;
26     
27     /**
28      * 為當限前登錄的用戶授予角色和權
29      */
30     @Override
31     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
32         return null;
33     }
34 
35     /**
36      * 驗證當前登錄的用戶
37      */
38     @Override
39     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
40         String userName=(String)token.getPrincipal();
41         Blogger blogger=bloggerService.getByUserName(userName);
42         if(blogger!=null){
43             SecurityUtils.getSubject().getSession().setAttribute("currentUser", blogger); // 當前用戶信息存到session中
44             AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(blogger.getUserName(),blogger.getPassword(),"xx");
45             return authcInfo;
46         }else{
47             return null;                
48         }
49     }
50 
51 }

6:並用工具類進行加鹽

 1 package com.xqc.util;
 2 
 3 import org.apache.shiro.crypto.hash.Md5Hash;
 4 
 5 /**
 6  * 加密工具
 7  *
 8  */
 9 public class CryptographyUtil {
10     
11     /**
12      * Md5加密
13      * @param str
14      * @param salt
15      * @return
16      */
17     public static String md5(String str,String salt){
18         return new Md5Hash(str,salt).toString();
19     }
20 
21     
22 }

 分角色賦予不同的權利啦!分角色回顯不同的信息啦!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM