博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Apache Shiro 快速入门实例
阅读量:6158 次
发布时间:2019-06-21

本文共 9860 字,大约阅读时间需要 32 分钟。

hot3.png

第一部分 什么是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 来自动生成数据表结构。 

/***  * 用户表  *   * @author Swinglife  *   */  @Table(name = "t_user")  @Entity  public class User {        @Id      @GeneratedValue(strategy = GenerationType.AUTO)      Integer id;      /** 用户名 **/      String username;      /** 密码 **/      String password;      /** 是否删除 **/      Integer isDelete;      /** 创建时间 **/      Date createDate;      //多对多用户权限表      @OneToMany(mappedBy = "user",cascade=CascadeType.ALL)      List
userRoles; 省略get set…. }
/****  * 角色表  *   * @author Swinglife  *   */  @Entity  @Table(name = "t_role")  public class Role {      @Id      @GeneratedValue(strategy = GenerationType.AUTO)      Integer id;      /**角色名**/      String name;      /**角色说明**/      String description;      }
/****  * 权限表  *   * @author Swinglife  *   */  @Entity  @Table(name = "t_permission")  public class Permission {        @Id      @GeneratedValue(strategy = GenerationType.AUTO)      Integer id;      /**token**/      String token;      /**资源url**/      String url;      /**权限说明**/      String description;      /**所属角色编号**/      Integer roleId;    }
/***  * 用户角色表  *   * @author Swinglife  *   */  @Entity  @Table(name = "t_user_role")  public class UserRole {        @Id      @GeneratedValue(strategy = GenerationType.AUTO)      Integer id;        @ManyToOne(cascade = CascadeType.ALL)      @JoinColumn(name = "userId", unique = true)      User user;      @ManyToOne      @JoinColumn(name = "roleId", unique = true)      Role role;    }

 

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

@Service  public class AccountService {        /****      * 通过用户名获取用户对象      *       * @param username      * @return      */      public User getUserByUserName(String username) {          User user = (User) dao.findObjectByHQL("FROM User WHERE username = ?", new Object[] { username });          return user;      }        /***      * 通过用户名获取权限资源      *       * @param username      * @return      */      public List
getPermissionsByUserName(String username) { System.out.println("调用"); User user = getUserByUserName(username); if (user == null) { return null; } List
list = new ArrayList
(); // System.out.println(user.getUserRoles().get(0).get); for (UserRole userRole : user.getUserRoles()) { Role role = userRole.getRole(); List
permissions = dao.findAllByHQL("FROM Permission WHERE roleId = ?", new Object[] { role.getId() }); for (Permission p : permissions) { list.add(p.getUrl()); } } return list; } // 公共的数据库访问接口 // 这里省略BaseDao dao的编写 @Autowired private BaseDao dao; }

 

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

package org.swinglife.shiro;    import java.util.List;    import org.apache.shiro.authc.AuthenticationException;  import org.apache.shiro.authc.AuthenticationInfo;  import org.apache.shiro.authc.AuthenticationToken;  import org.apache.shiro.authc.SimpleAuthenticationInfo;  import org.apache.shiro.authc.UsernamePasswordToken;  import org.apache.shiro.authz.AuthorizationInfo;  import org.apache.shiro.authz.SimpleAuthorizationInfo;  import org.apache.shiro.realm.AuthorizingRealm;  import org.apache.shiro.subject.PrincipalCollection;  import org.swinglife.model.User;  import org.swinglife.service.AccountService;    /****  * 自定义Realm  *   * @author Swinglife  *   */  public class MyShiroRealm extends AuthorizingRealm {        /***      * 获取授权信息      */      @Override      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {          //根据自己系统规则的需要编写获取授权信息,这里为了快速入门只获取了用户对应角色的资源url信息          String username = (String) pc.fromRealm(getName()).iterator().next();          if (username != null) {              List
pers = accountService.getPermissionsByUserName(username); if (pers != null && !pers.isEmpty()) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); for (String each : pers) { //将权限资源添加到用户信息中 info.addStringPermission(each); } return info; } } return null; } /*** * 获取认证信息 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) at; // 通过表单接收的用户名 String username = token.getUsername(); if (username != null && !"".equals(username)) { User user = accountService.getUserByUserName(username); if (user != null) { return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); } } return null; } /**用户的业务类**/ private AccountService accountService; public AccountService getAccountService() { return accountService; } public void setAccountService(AccountService accountService) { this.accountService = accountService; } }

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

5、编写LoginController:

package org.swinglife.controller;    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 org.springframework.web.bind.annotation.RequestMethod;  import org.springframework.web.portlet.ModelAndView;  import org.swinglife.model.User;  import org.swinglife.service.AccountService;    /****  * 用户登录Controller  *   * @author Swinglife  *   */  @Controller  public class LoginController {        /***      * 跳转到登录页面      *       * @return      */      @RequestMapping(value = "toLogin")      public String toLogin() {          // 跳转到/page/login.jsp页面          return "login";      }        /***      * 实现用户登录      *       * @param username      * @param password      * @return      */      @RequestMapping(value = "login")      public ModelAndView Login(String username, String password) {          ModelAndView mav = new ModelAndView();          User user = accountService.getUserByUserName(username);          if (user == null) {              mav.setView("toLogin");              mav.addObject("msg", "用户不存在");              return mav;          }          if (!user.getPassword().equals(password)) {              mav.setView("toLogin");              mav.addObject("msg", "账号密码错误");              return mav;          }          SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());          // 登录后存放进shiro token          UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());          Subject subject = SecurityUtils.getSubject();          subject.login(token);          // 登录成功后会跳转到successUrl配置的链接,不用管下面返回的链接。          mav.setView("redirect:/home");          return mav;      }        // 处理用户业务类      @Autowired      private AccountService accountService;  }

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

package org.swinglife.controller;    import org.springframework.stereotype.Controller;  import org.springframework.web.bind.annotation.RequestMapping;    @Controller  public class IndexController {        @RequestMapping("home")      public String index() {          System.out.println("登录成功");          return "home";      }  }

7、Shiro的配置文件.xml

/toLogin = authc
/home = authc, perms[/home]

 

loginUrl 用于配置登陆页

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

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

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

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

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

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

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

8、登陆页login.jsp

    

user login

username:

password:

${msg }

9、运行程序

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

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

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

shiro jar:http://download.csdn.net/detail/swingpyzf/8766673

项目源码:github:https://github.com/swinglife/shiro_ex

转载于:https://my.oschina.net/u/2391658/blog/852260

你可能感兴趣的文章
使用FMDB最新v2.3版本教程
查看>>
STM32启动过程--启动文件--分析
查看>>
垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
查看>>
淘宝的几个架构图
查看>>
linux后台运行程序
查看>>
Python异步IO --- 轻松管理10k+并发连接
查看>>
Oracle中drop user和drop user cascade的区别
查看>>
登记申请汇总
查看>>
Android Jni调用浅述
查看>>
CodeCombat森林关卡Python代码
查看>>
(二)Spring Boot 起步入门(翻译自Spring Boot官方教程文档)1.5.9.RELEASE
查看>>
Shell基础之-正则表达式
查看>>
JavaScript异步之Generator、async、await
查看>>
讲讲吸顶效果与react-sticky
查看>>
c++面向对象的一些问题1 0
查看>>
售前工程师的成长---一个老员工的经验之谈
查看>>
Get到的优秀博客网址
查看>>
老男孩教育每日一题-第107天-简述你对***的理解,常见的有哪几种?
查看>>
Python学习--time
查看>>
在OSCHINA上的第一篇博文,以后好好学习吧
查看>>