Shiro

Shiro

1、Shiro的简介

1.1Shiro特性 Shiro

Shiro把Shiro开发团队称为“应用程序的四大基石”——身份验证,授权,会话管理和加密作为其目标。

  • Authentication:有时也简称为“登录”,这是一个证明用户是他们所说的他们是谁的行为。
  • Authorization:访问控制的过程,也就是绝对“谁”去访问“什么”。
  • Session Management:管理用户特定的会话,即使在非 Web 或 EJB 应用程序。
  • Cryptography:通过使用加密算法保持数据安全同时易于使用。

1.2 Shiro架构

Shiro

Subject:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject,一个Subject可以是一个人,但它还可以代表第三方服务,daemon account,cron job,或其他类似的任何东西——基本上是当前正与软件进行交互的任何东西。

SecurityManager

SecurityManager是Shiro架构的心脏,并作为一种“保护伞”对象来协调内部的安全组件共同构成一个对象图。然而,一旦SecurityManager和它的内置对象图已经配置给一个应用程序,那么它单独留下来,且应用程序开发人员几乎使用他们所有的时间来处理Subject API。当你正与一个Subject进行交互时,实质上是幕后的 SecurityManager处理所有繁重的Subject安全操作。

quickStart:

Subject

//获取当前用户对象的Subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前用户拿到session
Session session = currentUser.getSession();
//判断当前的用户是否被认证
if (!currentUser.isAuthenticated())
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//是否获取角色
currentUser.hasRole("schwartz")

2、Springboot中集成

2.1 导入依赖

Shiro整合Spring依赖

 		<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.1</version>
        </dependency>

Thymeleaf依赖:

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>

2.2 两个Config

ShiroConfig UserRealm
Shiro
Shiro

2.3 Shiro登录拦截

注意@Bean和 @Configuration不能丢

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean:3
    @Bean
    public ShiroFilterFactoryBean getShiroFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证了才能访问
            user: 必须要拥有 记住我 功能才能用
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
        LinkedHashMap<String, String> filterMap =new LinkedHashMap<>();
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
        return bean;
    }
    //DefaultWebSecurityMangger: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();
    }

2.4 Shiro整合Mybatis

  • 导入依赖

     		  <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.3</version>
            </dependency>
    
  • application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    
mybatis:
  type-aliases-package: com.example.demo.pojo
  mapper-locations: classpath:mapper/*.xml    
  • 用户名和密码存入数据库中

UserRealm中:

 //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了认证");
        //用户名,密码 数据库中取
//        String name="root";
//        String password="123456";

        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        User user = userService.queryUserByName(userToken.getUsername());
        if(user==null){
            return null;
        }
//        if(!userToken.getUsername().equals(name)){
//            return  null;//抛出异常
//        }

        //密码认证
        return  new SimpleAuthenticationInfo("",user.getPwd(),"");


    }
  • Controller中
 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";
        }

    }
  • 权限操作(vip)

    ShiroConfig中

     //授权,正常情况下,没有授权会跳转到未授权的页面
            filterMap.put("/user/add","perms[user:add]");
    

    Controller中添加未授权的页面

    @RequestMapping("/noauth")
        @ResponseBody
        public String unauthorized(){
            return "未经授权无法访问此页面";
        }
    

    ShiroConfig中:

       //未授权的页面
            bean.setUnauthorizedUrl("/noauth");
    

    UserRealm中:

     //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了授权");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addStringPermission("user:add");
            return info;
        }
    

    对用户有区分,需在数据库中设置一个perm,设置权限等级

  • 设置后

    UserRealm认证中:

    return  new SimpleAuthenticationInfo(user,user.getPwd(),"");
    

    UserRealm授权中:

    //拿到当前登录的对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser =(User) subject.getPrincipal();
            info.addStringPermission(currentUser.getPerms());
            return info;
    

2.5 Shiro整合Thymeleaf

  • 导入依赖

    		<dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>
    
  • ShiroConfig中:

 @Bean
    //整合ShiroDialect :用来整合 Shiro和Thymeleaf
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
  • 前端
<html lang="en" xmlns:th="http://www.thymeleaf.org"
                xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<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>
上一篇:Go 设计模式 - 观察者模式


下一篇:高级数据结构6.2——线段树