7. 整合shiro,搭建粗粒度权限管理

Posted 旅鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7. 整合shiro,搭建粗粒度权限管理相关的知识,希望对你有一定的参考价值。

shiro是一个易用的权限管理框架,只需提供一个Realm即可在项目中使用,本文就将结合上一篇中搭建的权限模块、角色模块和用户模块来搭建一个粗粒度的权限管理系统,具体如下:
1. 添加shiro依赖和与thymeleaf集成的依赖,并更新项目:

 1 <dependency>
 2     <groupId>org.apache.shiro</groupId>
 3     <artifactId>shiro-spring</artifactId>
 4     <version>1.4.0</version>
 5 </dependency>
 6 <dependency>  
 7     <groupId>com.github.theborakompanioni</groupId>  
 8     <artifactId>thymeleaf-extras-shiro</artifactId>  
 9     <version>1.0.2</version>  
10 </dependency> 
pom.xml

2. 添加自定义Realm类,主要完成用户校验和授权的功能

 1 package com.lvniao.blog.config;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 import javax.annotation.Resource;
 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.authc.UsernamePasswordToken;
13 import org.apache.shiro.authz.AuthorizationInfo;
14 import org.apache.shiro.authz.SimpleAuthorizationInfo;
15 import org.apache.shiro.realm.AuthorizingRealm;
16 import org.apache.shiro.subject.PrincipalCollection;
17 import org.apache.shiro.util.ByteSource;
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.stereotype.Component;
20 
21 import com.lvniao.blog.mapper.UserMapper;
22 import com.lvniao.blog.model.User;
23 
24 @Component
25 public class ShiroRealm extends AuthorizingRealm {
26 
27     @Autowired
28     private UserMapper userMapper;
29     
30     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
31         String username = (String)principals.getPrimaryPrincipal();
32         User user = userMapper.getUserWithRoleByName(username);
33         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
34         Set<String> roles = new HashSet<String>();
35         Set<String> permissions = new HashSet<String>();
36         user.getRolesAndPermissions(roles, permissions);
37         authorizationInfo.setRoles(roles);
38         authorizationInfo.setStringPermissions(permissions);
39         return authorizationInfo;
40     }
41     
42     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
43         UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
44         String username = (String)usernamePasswordToken.getPrincipal();
45         String password = new String(usernamePasswordToken.getPassword());
46         if(userMapper.check(username, password) != null) {
47             User user = userMapper.getUserByName(username);
48             
49             SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getName(), 
50                     user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
51             
52             return authenticationInfo;
53         } else {
54             throw new AuthenticationException();
55         }
56     }
57 }
ShiroRealm

3. 添加ShiroConfiguration类,完成shiro的配置

 1 package com.lvniao.blog.config;
 2 
 3 import java.util.LinkedHashMap;
 4 import java.util.List;
 5 import java.util.Map;
 6 
 7 import org.apache.shiro.mgt.SessionsSecurityManager;
 8 import org.apache.shiro.realm.Realm;
 9 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
10 import org.apache.shiro.web.mgt.CookieRememberMeManager;
11 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
12 import org.springframework.beans.factory.annotation.Qualifier;
13 import org.springframework.context.annotation.Bean;
14 import org.springframework.context.annotation.Configuration;
15 import org.apache.shiro.mgt.SecurityManager;
16 
17 @Configuration
18 public class ShiroConfiguration{
19 
20     @Bean
21     public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
22         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
23 
24         // 必须设置 SecurityManager
25         shiroFilterFactoryBean.setSecurityManager(securityManager);
26 
27         shiroFilterFactoryBean.setLoginUrl("/admin/login");
28 
29         shiroFilterFactoryBean.setSuccessUrl("/admin/");
30 
31         Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
32         filterChainDefinitionMap.put("/css/**", "anon");
33         filterChainDefinitionMap.put("/js/**", "anon");
34         filterChainDefinitionMap.put("/images/**", "anon");
35         filterChainDefinitionMap.put("/fonts/**", "anon");
36         filterChainDefinitionMap.put("/admin/loginaction", "anon");
37 
38         filterChainDefinitionMap.put("/**", "authc");
39 
40         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
41         System.out.println("Shiro拦截器工厂类注入成功");
42         return shiroFilterFactoryBean;
43     }
44 
45     @Bean
46     public SecurityManager securityManager() {
47         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
48         // 设置realm.
49         securityManager.setRealm(ShiroRealm());
50         return securityManager;
51     }
52 
53     @Bean
54     public ShiroRealm ShiroRealm() {
55         ShiroRealm shiroRealm = new ShiroRealm();
56         return shiroRealm;
57     }
58 
59     @Bean
60     public ShiroDialect shiroDialect() {
61         return new ShiroDialect();
62     }
63 }
ShiroConfiguration

因为添加了filterChainDefinitionMap.put("/**", "authc"),所以shiro会对所有请求进行验证,包括静态资源,所以需要通过如: filterChainDefinitionMap.put("/css/**", "anon");这样的来使静态资源请求不被拦截。通过这三个步骤就已经把shiro配置好了,下面就完成登录部分:
4. 添加登录action

 1 package com.lvniao.blog.admin.controller;
 2 
 3 import java.util.List;
 4 
 5 import org.apache.shiro.SecurityUtils;
 6 import org.apache.shiro.authc.IncorrectCredentialsException;
 7 import org.apache.shiro.authc.UnknownAccountException;
 8 import org.apache.shiro.authc.UsernamePasswordToken;
 9 import org.apache.shiro.crypto.hash.Md5Hash;
10 import org.apache.shiro.subject.Subject;
11 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.stereotype.Controller;
13 import org.springframework.ui.Model;
14 import org.springframework.web.bind.annotation.RequestMapping;
15 import org.springframework.web.servlet.ModelAndView;
16 
17 import com.lvniao.blog.mapper.MenuMapper;
18 import com.lvniao.blog.mapper.UserMapper;
19 import com.lvniao.blog.model.Menu;
20 import com.lvniao.blog.model.User;
21 import com.lvniao.blog.util.Constant;
22 
23 @Controller
24 @RequestMapping("/admin")
25 public class AdminController {
26     
27     @Autowired
28     private UserMapper userMapper;
29     
30     @Autowired
31     private MenuMapper menuMapper;
32     
33     @RequestMapping("/")
34     public String index(Model model) {
35         model.addAttribute("menus", menuMapper.getParentMenu());
36         return "admin/index";
37     }
38     
39     @RequestMapping("/menu")
40     public String menu(Model model) {
41         return "admin/menu1";
42     }
43     
44     @RequestMapping("/login")
45     public String login() {
46         return "admin/login";
47     }
48     
49     @RequestMapping("/loginaction")
50     public ModelAndView loginAction(User user) {
51         Subject subject = SecurityUtils.getSubject();
52         if(!subject.isAuthenticated()) {
53             
54             try {
55                 User u = userMapper.getUserByName(user.getName());
56                 if(u != null) {
57                     String password = new Md5Hash(user.getPassword(), u.getSalt()).toString();
58                     UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), password);
59                     token.setRememberMe(false);
60                     subject.login(token);
61                     User currentUser = userMapper.getUserByName(user.getName());
62                     subject.getSession().setAttribute(Constant.CurrentUser, currentUser);
63                     return new ModelAndView("redirect:/admin/");
64                 }
65                 
66             } catch(UnknownAccountException ex) {
67                 
68             } catch (IncorrectCredentialsException ex) {
69                 
70             } catch (Exception ex) {
71                 
72             }
73         }
74         return new ModelAndView("redirect:/admin/login");
75     }
76 }
AdminController

5. 添加登录页

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>lvniao</title>
 5     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 6     <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
 7     <link rel="stylesheet" th:href="@{/css/base.css}"/>
 8     <link rel="stylesheet" th:href="@{/css/font-awesome.css}"/>
 9     <link rel="stylesheet" th:href="@{/css/login.css}"/>
10     <script th:src="@{/js/jquery-3.2.1.js}"></script>
11     <script th:src="@{/statics/js/base.js}"></script>
12     <style>
13         *{
14             margin:0px;
15             padding:0px;
16         }
17         body{
18             background-image:url("/images/loginbg.jpg") ;
19             background-size:100% 100%;
20         }
21     </style>
22 </head>
23 <body>
24     <form class="login" th:action="@{/admin/loginaction}" th:method="post">
25         <div class="header">
26             <h1>登录</h1>
27         </div>
28         <div class="text name">
29             <input type="text" class="input" name="name" placeholder="用户名"/>
30         </div>
31         <div class="text password">
32             <input type="password" class="input" name="password" placeholder="密码"/>
33         </div>
34         <button type="submit" class="button">登录</button>
35         <div class="foot">
36         </div>
37     </form>
38 </body>
39 </html>
login.html

其中在css中使用url可以按照正常的使用,不用按照html中添加资源的方式。

登录成功后就会跳转到/admin/页

6. 因为在上一篇文章中以及添加好了角色授权和给用户赋角色,而现在要做的就是使用shiro来对界面做粗粒度权限管理,shiro在验证授权时需要获得用户的角色列表和权限列表,所以首先就修改User.java,增加获取角色和权限的接口,代码如下:

  1 package com.lvniao.blog.model;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Set;
  6 
  7 import com.lvniao.blog.model.Permission;
  8 import com.lvniao.blog.model.Role;
  9 import com.lvniao.blog.util.StringUtil;
 10 
 11 public class User {
 12 
 13 private Long id;
 14     
 15     private String name;
 16     
 17     private String password;
 18     
 19     private String salt;
 20     
 21     private Boolean locked;
 22 
 23     private List<Role> roles = new ArrayList<Role>();
 24     
 25     private String rolesStr = null;
 26     
 27     public Long getId() {
 28         return id;
 29     }
 30 
 31     public void setId(Long id) {
 32         this.id = id;
 33     }
 34 
 35     public String getName() {
 36         return name;
 37     }
 38 
 39     public void setName(String name) {
 40         this.name = name;
 41     }
 42 
 43     public String getPassword() {
 44         return password;
 45     }
 46 
 47     public void setPassword(String password) {
 48         this.password = password;
 49     }
 50 
 51     public String getSalt() {
 52         return salt;
 53     }
 54 
 55     public void setSalt(String salt) {
 56         this.salt = salt;
 57     }
 58 
 59     public Boolean isLocked() {
 60         return locked;
 61     }
 62 
 63     public void setLocked(Boolean locked) {
 64         this.locked = locked;
 65     }
 66 
 67     public List<Role> getRoles() {
 68         return roles;
 69     }
 70 
 71     public void setRoles(List<Role> roles) {
 72         this.roles = roles;
 73     }
 74 
 75     public String getRolesStr() {
 76         if(StringUtil.isNullOrEmpty(rolesStr)) {
 77             if(getRoles() != null && getRoles().size() > 0) {
 78                 StringBuffer sb = new StringBuffer();
 79                 
 80                 for(Role r : getRoles()) {
 81                     if(r != null) {
 82                         sb.append(r.getId());
 83                         sb.append(",");
 84                     }
 85                 }
 86                 if(sb.length() > 0) {
 87                     rolesStr = sb.toString().substring(0, sb.length() - 1);
 88                 }
 89             }
 90         }
 91         return rolesStr;
 92     }
 93 
 94     public void setRolesStr(String rolesStr) {
 95         this.rolesStr = rolesStr;
 96     }
 97 
 98     public void getRolesAndPermissions(Set<String> roleres, Set<String> permissionres) {
 99         getRolesAndPermissions(getRoles(), roleres, permissionres);
100     }
101     
102     private void getRolesAndPermissions(List<Role> roles, Set<String> roleres, Set<String> permissionres) {
103         for(Role role : roles) {
104             roleres.add(role.getAlias());
105             for(Permission p : role.getPermissions

以上是关于7. 整合shiro,搭建粗粒度权限管理的主要内容,如果未能解决你的问题,请参考以下文章

shiro--颗粒度

了解权限控制框架shiro 之实际应用.

了解权限控制框架shiro 之实际应用.

Shiro入门这篇就够了Shiro的基础知识回顾URL拦截

粗粒度与细粒度权限控制

粗粒度与细粒度权限控制