Shiro学习总结(2)——Apache Shiro快速入门教程

第一部分 什么是Apache Shiro

1、什么是 apache shiro :

Apache Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理

如同 spring security 一样都是是一个权限安全框架,但是与Spring Security相比,在于他使用了和比较简洁易懂的认证和授权方式。

2、Apache Shiro 的三大核心组件:

1、Subject :当前用户的操作

2、SecurityManager:用于管理所有的Subject

3、Realms:用于进行权限信息的验证

Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。

SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。

Realms:Realms则是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。

3、Authentication 和 Authorization

在shiro的用户权限认证过程中其通过两个方法来实现:

1、Authentication:是验证用户身份的过程。

2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

4、其他组件:

除了以上几个组件外,Shiro还有几个其他组件:

1、SessionManager :Shiro为任何应用提供了一个会话编程范式。

2、CacheManager :对Shiro的其他组件提供缓存支持。

5、Shiro 完整架构图:

图片转自:http://kdboy.iteye.com/blog/1154644

第二部分 Apache Shiro 整合Spring的Web程序构建

1、准备工具:

持久层框架:Hibernate4  这边我使用了hibernate来对数据持久层进行操作

控制显示层框架:SpringMVC 这边我使用了SpringMVC实际开发中也可以是其他框架

数据库MySQL

准备好所需要的jar放到项目中。

2、创建数据库:

首先需要四张表,分别为 user(用户)、role(角色)、permission(权限)、userRole(用户角色关系表)

这边分别创建四张表的实体类,通过Hiberante的hibernate.hbm2ddl.auto属性的update 来自动生成数据表结构。

[java] view
plain
 copy

print?

  1. /***
  2. * 用户表
  3. *
  4. * @author Swinglife
  5. *
  6. */
  7. @Table(name = "t_user")
  8. @Entity
  9. public class User {
  10. @Id
  11. @GeneratedValue(strategy = GenerationType.AUTO)
  12. Integer id;
  13. /** 用户名 **/
  14. String username;
  15. /** 密码 **/
  16. String password;
  17. /** 是否删除 **/
  18. Integer isDelete;
  19. /** 创建时间 **/
  20. Date createDate;
  21. //多对多用户权限表
  22. @OneToMany(mappedBy = "user",cascade=CascadeType.ALL)
  23. List<UserRole> userRoles;
  24. 省略get set….
  25. }

[java] view
plain
 copy

print?

  1. /****
  2. * 角色表
  3. *
  4. * @author Swinglife
  5. *
  6. */
  7. @Entity
  8. @Table(name = "t_role")
  9. public class Role {
  10. @Id
  11. @GeneratedValue(strategy = GenerationType.AUTO)
  12. Integer id;
  13. /**角色名**/
  14. String name;
  15. /**角色说明**/
  16. String description;
  17. }

[java] view
plain
 copy

print?

  1. /****
  2. * 权限表
  3. *
  4. * @author Swinglife
  5. *
  6. */
  7. @Entity
  8. @Table(name = "t_permission")
  9. public class Permission {
  10. @Id
  11. @GeneratedValue(strategy = GenerationType.AUTO)
  12. Integer id;
  13. /**token**/
  14. String token;
  15. /**资源url**/
  16. String url;
  17. /**权限说明**/
  18. String description;
  19. /**所属角色编号**/
  20. Integer roleId;
  21. }

[java] view
plain
 copy

print?

  1. /***
  2. * 用户角色表
  3. *
  4. * @author Swinglife
  5. *
  6. */
  7. @Entity
  8. @Table(name = "t_user_role")
  9. public class UserRole {
  10. @Id
  11. @GeneratedValue(strategy = GenerationType.AUTO)
  12. Integer id;
  13. @ManyToOne(cascade = CascadeType.ALL)
  14. @JoinColumn(name = "userId", unique = true)
  15. User user;
  16. @ManyToOne
  17. @JoinColumn(name = "roleId", unique = true)
  18. Role role;
  19. }

3、编写操作用户业务的Service:

[java] view
plain
 copy

print?

  1. @Service
  2. public class AccountService {
  3. /****
  4. * 通过用户名获取用户对象
  5. *
  6. * @param username
  7. * @return
  8. */
  9. public User getUserByUserName(String username) {
  10. User user = (User) dao.findObjectByHQL("FROM User WHERE username = ?", new Object[] { username });
  11. return user;
  12. }
  13. /***
  14. * 通过用户名获取权限资源
  15. *
  16. * @param username
  17. * @return
  18. */
  19. public List<String> getPermissionsByUserName(String username) {
  20. System.out.println("调用");
  21. User user = getUserByUserName(username);
  22. if (user == null) {
  23. return null;
  24. }
  25. List<String> list = new ArrayList<String>();
  26. // System.out.println(user.getUserRoles().get(0).get);
  27. for (UserRole userRole : user.getUserRoles()) {
  28. Role role = userRole.getRole();
  29. List<Permission> permissions = dao.findAllByHQL("FROM Permission WHERE roleId = ?", new Object[] { role.getId() });
  30. for (Permission p : permissions) {
  31. list.add(p.getUrl());
  32. }
  33. }
  34. return list;
  35. }
  36. // 公共的数据库访问接口
  37. // 这里省略BaseDao dao的编写
  38. @Autowired
  39. private BaseDao dao;
  40. }

4、编写shiro组件自定义Realm:

[java] view
plain
 copy

print?

  1. package org.swinglife.shiro;
  2. import java.util.List;
  3. import org.apache.shiro.authc.AuthenticationException;
  4. import org.apache.shiro.authc.AuthenticationInfo;
  5. import org.apache.shiro.authc.AuthenticationToken;
  6. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  7. import org.apache.shiro.authc.UsernamePasswordToken;
  8. import org.apache.shiro.authz.AuthorizationInfo;
  9. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  10. import org.apache.shiro.realm.AuthorizingRealm;
  11. import org.apache.shiro.subject.PrincipalCollection;
  12. import org.swinglife.model.User;
  13. import org.swinglife.service.AccountService;
  14. /****
  15. * 自定义Realm
  16. *
  17. * @author Swinglife
  18. *
  19. */
  20. public class MyShiroRealm extends AuthorizingRealm {
  21. /***
  22. * 获取授权信息
  23. */
  24. @Override
  25. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
  26. //根据自己系统规则的需要编写获取授权信息,这里为了快速入门只获取了用户对应角色的资源url信息
  27. String username = (String) pc.fromRealm(getName()).iterator().next();
  28. if (username != null) {
  29. List<String> pers = accountService.getPermissionsByUserName(username);
  30. if (pers != null && !pers.isEmpty()) {
  31. SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
  32. for (String each : pers) {
  33. //将权限资源添加到用户信息中
  34. info.addStringPermission(each);
  35. }
  36. return info;
  37. }
  38. }
  39. return null;
  40. }
  41. /***
  42. * 获取认证信息
  43. */
  44. @Override
  45. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
  46. UsernamePasswordToken token = (UsernamePasswordToken) at;
  47. // 通过表单接收的用户名
  48. String username = token.getUsername();
  49. if (username != null && !"".equals(username)) {
  50. User user = accountService.getUserByUserName(username);
  51. if (user != null) {
  52. return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
  53. }
  54. }
  55. return null;
  56. }
  57. /**用户的业务类**/
  58. private AccountService accountService;
  59. public AccountService getAccountService() {
  60. return accountService;
  61. }
  62. public void setAccountService(AccountService accountService) {
  63. this.accountService = accountService;
  64. }
  65. }

上述类继承了Shiro的AuthorizingRealm类 实现了AuthorizationInfo和AuthenticationInfo两个方法,用于获取用户权限和认证用户登录信息

5、编写LoginController:

[java] view
plain
 copy

print?

  1. package org.swinglife.controller;
  2. import org.apache.shiro.SecurityUtils;
  3. import org.apache.shiro.authc.UsernamePasswordToken;
  4. import org.apache.shiro.subject.Subject;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.portlet.ModelAndView;
  10. import org.swinglife.model.User;
  11. import org.swinglife.service.AccountService;
  12. /****
  13. * 用户登录Controller
  14. *
  15. * @author Swinglife
  16. *
  17. */
  18. @Controller
  19. public class LoginController {
  20. /***
  21. * 跳转到登录页面
  22. *
  23. * @return
  24. */
  25. @RequestMapping(value = "toLogin")
  26. public String toLogin() {
  27. // 跳转到/page/login.jsp页面
  28. return "login";
  29. }
  30. /***
  31. * 实现用户登录
  32. *
  33. * @param username
  34. * @param password
  35. * @return
  36. */
  37. @RequestMapping(value = "login")
  38. public ModelAndView Login(String username, String password) {
  39. ModelAndView mav = new ModelAndView();
  40. User user = accountService.getUserByUserName(username);
  41. if (user == null) {
  42. mav.setView("toLogin");
  43. mav.addObject("msg", "用户不存在");
  44. return mav;
  45. }
  46. if (!user.getPassword().equals(password)) {
  47. mav.setView("toLogin");
  48. mav.addObject("msg", "账号密码错误");
  49. return mav;
  50. }
  51. SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());
  52. // 登录后存放进shiro token
  53. UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
  54. Subject subject = SecurityUtils.getSubject();
  55. subject.login(token);
  56. // 登录成功后会跳转到successUrl配置的链接,不用管下面返回的链接。
  57. mav.setView("redirect:/home");
  58. return mav;
  59. }
  60. // 处理用户业务类
  61. @Autowired
  62. private AccountService accountService;
  63. }

6、编写信息认证成功后的跳转页面:

[java] view
plain
 copy

print?

  1. package org.swinglife.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. public class IndexController {
  6. @RequestMapping("home")
  7. public String index() {
  8. System.out.println("登录成功");
  9. return "home";
  10. }
  11. }

7、Shiro的配置文件.xml

[java] view
plain
 copy

print?

  1. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  2. <property name="securityManager" ref="securityManager" />
  3. <property name="loginUrl" value="/toLogin" />
  4. <property name="successUrl" value="/home" />
  5. <property name="unauthorizedUrl" value="/403" />
  6. <property name="filterChainDefinitions">
  7. <value>
  8. /toLogin = authc <!-- authc 表示需要认证才能访问的页面 -->
  9. /home = authc, perms[/home]  <!-- perms 表示需要该权限才能访问的页面 -->
  10. </value>
  11. </property>
  12. </bean>
  13. <bean id="myShiroRealm" class="org.swinglife.shiro.MyShiroRealm">
  14. <property name="accountService" ref="accountService" />
  15. </bean>
  16. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  17. <property name="realm" ref="myShiroRealm"></property>
  18. </bean>
  19. <bean id="accountService" class="org.swinglife.service.AccountService"></bean>
  20. <!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
  21. <property name="cacheManager" ref="cacheManager" /> </bean> -->

loginUrl 用于配置登陆页

successUrl 用于配置登录成功后返回的页面,不过该参数只会在当登录页面中并没有任何返回页面时才会生效,否则会跳转到登录Controller中的指定页面。

unauthorizedUrl 用于配置没有权限访问页面时跳转的页面

filterChainDefinitions:apache shiro通过filterChainDefinitions参数来分配链接的过滤,资源过滤有常用的以下几个参数:

1、authc 表示需要认证的链接

2、perms[/url] 表示该链接需要拥有对应的资源/权限才能访问

3、roles[admin] 表示需要对应的角色才能访问

4、perms[admin:url] 表示需要对应角色的资源才能访问

8、登陆页login.jsp

[html] view
plain
 copy

print?

  1. <body>
  2. <h1>user login</h1>
  3. <form action="login" method="post">
  4. username:<input type="text" name="username"><p>
  5. password:<input type="password" name="password">
  6. <p>
  7. ${msg }
  8. <input type="submit" value="submit">
  9. </form>
  10. </body>

9、运行程序

在数据库中添加一条用户、角色、以及权限数据,并且在关联表中添加一条关联数据:

在浏览器中访问: home页面 就会跳转到登录页面:

最后输入 账号密码 就会跳转到登录成功页面。

时间: 2024-08-03 17:30:06

Shiro学习总结(2)——Apache Shiro快速入门教程的相关文章

架构设计:系统间通信(36)——Apache Camel快速入门(上)

1.本专题主旨 1-1.关于技术组件 在这个专题中,我们介绍了相当数量技术组件:Flume.Kafka.ActiveMQ.Rabbitmq.Zookeeper.Thrift .Netty.DUBBO等等,还包括本文要进行介绍的Apache Camel.有的技术组件讲得比较深入,有的技术组件则是点到为止.于是一些读者朋友发来信息向我提到,这个专题的文章感觉就像一个技术名词的大杂烩,并不清楚作者的想要通过这个专题表达什么思想. 提出这个质疑的朋友不在少数,所以我觉得有必要进行一个统一的说明.这个专题

Python学习基础篇第一篇——快速入门(适合初学者)

一.Python学习基础篇第一篇--(快速入门) 建议从Python2.7开始学习,Python2.7可以支持扩展大量的第三方类库,是目前比较成熟的版本 编写代码的软件推荐将python自带的IDLE和PyCharm集成IDE结合起来使用 1.1 Python命令行 Python命令行将以 >>> 开始,比如 >>>print 'Hello World!' 对于验证简单的命令可以在python自带的IDLE中完成  1.2 在Python自带的IDLE写一段小程序 在所

[shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证

本文地址:http://blog.csdn.net/sushengmiyan/article/details/39933993 shiro官网:http://shiro.apache.org/ shiro中文手册:http://wenku.baidu.com/link?url=ZnnwOHFP20LTyX5ILKpd_P94hICe9Ga154KLj_3cCDXpJWhw5Evxt7sfr0B5QSZYXOKqG_FtHeD-RwQvI5ozyTBrMAalhH8nfxNzyoOW21K 本文作

架构设计:系统间通信(38)——Apache Camel快速入门(下1)

======================= (接上文<架构设计:系统间通信(37)--Apache Camel快速入门(中)>) 3-5-2-3循环动态路由 Dynamic Router 动态循环路由的特点是开发人员可以通过条件表达式等方式,动态决定下一个路由位置.在下一路由位置处理完成后Exchange将被重新返回到路由判断点,并由动态循环路由再次做出新路径的判断.如此循环执行直到动态循环路由不能再找到任何一条新的路由路径为止.下图来源于官网(http://camel.apache.or

架构设计:系统间通信(37)——Apache Camel快速入门(中)

========================== (接上文<架构设计:系统间通信(36)--Apache Camel快速入门(上)>) (补上文:Endpoint重要的漏讲内容) 3-1-2.特殊的Endpoint Direct Endpoint Direct用于在两个编排好的路由间实现Exchange消息的连接,上一个路由中由最后一个元素处理完的Exchange对象,将被发送至由Direct连接的下一个路由起始位置(http://camel.apache.org/direct.html)

NetBeans工具学习之道:NetBeans IDE Java 快速入门教程

欢迎使用 NetBeans IDE! 本教程通过指导您创建一个简单的 "Hello World" Java 控制台应用程序,简要介绍 NetBeans IDE 工作流.学习完本教程后,您将对如何在 IDE 中创建和运行应用程序有一个基本了解. 学习完本教程所需的时间不到 10 分钟. 学完本教程后,您可以转至文档.培训和支持页中链接的学习资源.这些学习资源提供了综合性教程,其中重点介绍适用各种应用程序类型的更多 IDE 功能和编程技巧.如果您不希望创建 "Hello Worl

架构设计:系统间通信(39)——Apache Camel快速入门(下2)

======================== (接上文:<架构设计:系统间通信(38)--Apache Camel快速入门(下1)>) 4-2-1.LifecycleStrategy LifecycleStrategy接口按照字面的理解是一个关于Camel中元素生命周期的规则管理器,但实际上LifecycleStrategy接口的定义更确切的应该被描述成一个监听器: 当Camel引用程序中发生诸如Route加载.Route移除.Service加载.Serivce移除.Context启动或者

C语言快速入门教程(二)

C语言快速入门教程(二) C语言的基本语法 本节学习路线图: 引言: C语言,顾名思义就是一门语言,可以类比一下英语; 你要说出一个英语的句子需要:  单词  +  语法!  将单词按照一定的语法拼凑起来就成了一个英语句子了; C语言同样是这样,只不过单词可以理解为一些固定的知识点,而语法可以理解为算法(可以理解为解决问题的方法) 在这一节中我们就对固定知识点中的语言描述与数据存储进行解析! 1.C语言的基本元素 1.1  标识符 什么是标识符? 答:在C语言中,符号常量,变量,数组,函数等都需

CMake快速入门教程-实战

http://www.ibm.com/developerworks/cn/linux/l-cn-cmake/ http://blog.csdn.net/dbzhang800/article/details/6314073 http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html http://blog.sina.com.cn/s/blog_4aa4593d0100q3bt.html http://hahack.com/c