Shiro入门 + 案例001

架构内容参考https://blog.csdn.net/liyiming2017/article/details/78201713/

shiro架构内容

  • Apache Shiro是一个Java安全框架,执行身份验证、授权、密码和会话管理(SpringSecurity 也是一款好用的Java安全框架可以对比学习)。

  • High-Level Overview

  • Shiro’s architecture has 3 primary concepts: the Subject, SecurityManager and Realms.(shiro架构有三个主要概念Subject、SecurityManager 和Realms)。

    在这里插入图片描述

    • subject: 即“当前操作用户”。这个“用户”可以是和软件交互的任何事物。
    • SecurityManager:Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。就是说,一旦程序中的SecurityManager和他内部对象已经配置好,通常上就不用再管他,程序的开发人员几乎大部分时间都会花在Subject API上。(Facade模式)
    • Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
  • Detailed Architecture

  • The following diagram shows Shiro’s core architectural concepts

在这里插入图片描述

  • Subject

    安全领域层面命名的,当前和系统交互的实体(用户,第三方服务,定时任务等等)

  • SecurityManager(管理所有subject)

    SecurityManager是Shiro架构的核心。他很像是一个伞对象,来协调他所管理的组件,确保她们配合丝滑。它同时管理Shiro视角的每一个用户,他知道怎么执行每个用户的安全操作。

  • Authenticator(认证)

    Authenticator组件负责执行用户的登录操作。当用户尝试登录时,Authenticator会执行登录逻辑。Authenticator知道怎么和存储用户账户信息的一个或多个Realm协调工作。Realm中维护的数据用来检查用户身份,确保这个用户就是他所说的那个用户。

  • Authentication Strategy

    如果配置了多个Realm,AuthenticationStrategy将会协调Realm来确定条件来判断认证成功或者失败。(例如,如果一个realm成功了,但是其他的失败了,那么登录成功了吗?必须所有的realm都成功?还是仅是第一个?)

  • Authorizer(授权)

    Authorizer组件负责确保用户的访问控制。说白了,他就是管控用户可以或者不可以做什么事情。就像Authenticator,Authorizer也知道如何和多种数据源协调来访问role和permission信息。Authorizer使用这些信息来验证用户是否允许做一个给定的操作。

  • SessionManager

    SessionManager负责创建和管理用户的session生命周期,在任何环境中都可以给用户提供健壮的session体验。这在安全框架世界中是第一无二的特性----Shiro在任何环境,甚至没有Web/servlet或者EJB的环境中,都具备原生管理用户session的能力。默认情况下,Shiro会尽可能使用已经存在的session机制(比如Servlet Container),但是如果没有存在的session机制,例如在独立的程序或者非web环境,他会使用内置的企业session管理来提供同样的编程体验。既有的SessionDAO允许任使用何数据源持久化session

  • SessionDAO

    SessionManager操作SessionDAO来执行session持久化(CRUD)操作。这可以允许任何数据存储被插入到session管理的基础设施中。

  • CacheManager

    CacheManager创建和管理其它Shiro组件使用的缓存实例生命周期。因为Shiro认证、授权、session管理中可以访问多种后端数据源,缓存一直以来都是最优级别的架构特性,来提高使用这些数据的性能。任何的现代开源或者企业级缓存产品都可以插入到Shiro中来提供快速高效的用户体验。

  • Cryptography(密码加密)

    Cryptography对于企业级安全框架是顺理成章的附加物。Shiro的crypto包含有易于使用和理解的密码工具,Hash(也称作摘要)和多种多样的编码实现。这个包中所有的类都精心设计以确保易于使用和理解。任何使用过java原生加密包的都知道它像驯兽一样困难。Shiro的API简化了Java机制,使得普通人也可以很简单的去使用。

  • Realms

    如上文所述,Realms在Shiro和你应用的安全数据间扮演着桥梁或者连接器的角色。当发生一次真实的安全数据交互,比如用户登录和鉴权,Shiro会从程序配置好的一或多个Realm中查询很多次数据。你可以配置你所需要的任意数量的Realm,Shrio在授权和鉴权的时候会去协调使用他们。

  • The SecurityManager

    由于Shiro的API鼓励以Subject为中心的编程方法,绝大多数开发者很少直接和SecurityManager打交道。(框架开发者可能有时会觉得它很有用)。即使这样,去了解SecurityManager如何工作还是很重要的,尤其是当你在给应用配置SecurityManager时。

  • Design

    Shiro的默认实现中,包含如下:

    授权
    鉴权
    session管理
    cache管理
    Realm管理
    事件传播
    Rmember Me服务
    Subject创建
    登出及更多

shiro简单案例

引入依赖

  • pom.xml

    在这里插入图片描述在这里插入图片描述

Java类

  • User.java
    //lombok
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
        private String perms;
    }
    
  • MyController.java
    @Controller
    public class MyController {
        @RequestMapping({"/","/toIndex"})
        public String toIndex(Model model){
            model.addAttribute("msg","hello,shiro");
            return "index";
        }
    
        @RequestMapping("/user/add")
        public String add(){
            return "user/add";
        }
        @RequestMapping("/user/update")
        public String update(){
            return "user/update";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    
        @RequestMapping("/login")
        public String login(String username,String password,Model model){
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登陆数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
            try {
                subject.login(token);//执行登陆方法
                return "index";
            } catch (UnknownAccountException e) {//用户名不存在
                model.addAttribute("msg","用户名错误");
                return "login";
            }catch (IncorrectCredentialsException e) {//密码不存在
                model.addAttribute("msg","密码错误");
                return "login";
            }
        }
        @RequestMapping("/noauth")
        @ResponseBody
        public String unauthorized(){
            return "未经授权无法访问此页面";
        }
    }
    
  • UserService.java
    public interface UserService {
        public User queryUserByName(String name);
    }
    
  • UserServiceImpl.java
    public class UserServiceImpl implements UserService {
        @Autowired
        UserMapper userMapper;
    
        public User queryUserByName(String name) {
            return userMapper.queryUserByName(name);
        }
    }
    
  • UserMapper.java
    @Repository
    @Mapper
    public interface UserMapper {
        public User queryUserByName(String name);
    }
    
  • UserMapper.xml
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper>
        <select id="queryUserByName" parameterType="String" resultType="User">
            select * from user where name = #{name}
        </select>
    </mapper>
    
  • 下边是关键代码
  • ShiroConfig.java
    @Configuration
    public class ShiroConfig {
    
        //ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
    
            //添加shiro的内置过滤器
            /*
                anon: 无需认证就可以访问
                authc: 必须认证了才能访问
                user: 必须拥有 记住我功能 才能用
                perm: 拥有对某个资源的权限才能访问;
                roles: 拥有某个角色权限才能访问
             */
            //拦截
            Map<String, String> filterMap = new LinkedHashMap();
    
            //授权
            filterMap.put("/user/add","perms[user:add]");
            filterMap.put("/user/update","perms[user:update]");
            //filterMap.put("/user/add","authc");
            //filterMap.put("/user/update","authc");
            filterMap.put("/user/*","authc");
    
            bean.setFilterChainDefinitionMap(filterMap);
    
            //设置登录的请求
            bean.setLoginUrl("/toLogin");
            //未授权页面
            bean.setUnauthorizedUrl("/noauth");
            return bean;
        }
    
        //DefaultWebSecurityManager:2
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        //创建realm对象,需要自定义类:1
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
    
        //整合shiroDialect:用来整合shiro thymeleaf
        @Bean
        public ShiroDialect getShiroDialect(){
            return new ShiroDialect();
        }
    }
    
    
  • UserRealm.java
    	//自定义的UserRealm
    public class UserRealm extends AuthorizingRealm {
    //public class UserRealm  {
    
        @Autowired
        UserService userService;
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=》授权doGetAuthorizationInfo");
            //
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //        info.addStringPermission("user:add");
    
            //拿到当前登陆的这个对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User) subject.getPrincipal();
            //设置当前用户权限
            if(null != currentUser.getPerms()){
                info.addStringPermission(currentUser.getPerms());
            }
            return info;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了=》认证doGetAuthorizationInfo");
    
    
            //用户名、密码  数据库中取
            /*String name = "root";
            String password = "111111";*/
    
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //冲数据库中拿数据
            User user = userService.queryUserByName(userToken.getUsername());
            if(user == null){//没有这个人  UnknownAccountException
                return null;
            }
    
            Subject currentSubject = SecurityUtils.getSubject();
            Session session = currentSubject.getSession();
            session.setAttribute("loginUser",user);
    
            //可以加密12345  MD5:ea8a706c4c34a168 MD5盐值加密:ea8a706c4c34a168admin
            //密码认证 shiro做
            return new SimpleAuthenticationInfo(user,user.getPwd(),"");
        }
    }
    
    
  • 静态页面
  • index.html
    <body>
        <h1>首页</h1>
        <div th:if="${session.loginUser==null}">
            <a th:href="@{/toLogin}">登陆</a>
        </div>
    
        <p th:text="${msg}"></p>
    
        <div shiro:hasPermission="user:add">
        <a th:href="@{/user/add}">add</a>
        </div>
        |
        <div shiro:hasPermission="user:update">
        <a th:href="@{/user/update}">update</a>
        </div>
    </body>
    
  • login.html
    <body>
    
    <h1>登录</h1>
    <hr>
    <p th:text="${msg}" style="color:red;"></p>
    
    <form th:action="@{/login}">
        <p>用户名: <input type="text" name="username"></p>
        <p>密码: <input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>
    </body>
    
  • user/add.html
    <body>
    <h1>add</h1>
    </body>
    
  • user/update.html
    <body>
    <h1>update</h1>
    </body>
    
  • application.yml
    server:
      port:8080
    spring:
      datasource:
        driverClassName: org.h2.Driver
        url: jdbc:h2:~/security #数据库名称test
        username: lucky #数据库用户名 默认sa
        password: 123123 #数据库密码,第一次随便填
      h2:
        console:
          path: /h2-console/safe
          enabled: true
    mybatis:
      mapper-locations: classpath:mapper/*Mapper.xml
      typeAliasesPackage: com.baiye.pojo
    
  • 数据库内容

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值