Shiro整合springboot简单使用

Shiro介绍

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

主要功能

三个核心组件:Subject, SecurityManager 和 Realms.

  • Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
    Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
  • SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
  • Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
      从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
      Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

使用shiro整合SpringBoot

  • 1.1 创建Shiro环境
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>
  • 1.2 配置Shiro
    – 测试环境配置yml
# 开发阶段,建议关闭thymeleaf的缓存,不然没有办法看到实时画面
spring.thymeleaf.cache=false
# 去掉H5的语法验证
spring.thymeleaf.mode=LEGACYHTML5

– 定义类 config.ShiroConfig

package com.netft.config;

import com.netft.realm.MyRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author: fengT
 * @date: 2020/7/23 0023 下午 15:42
 * @modified by
 */

// 标记当前类是一个Spring的配置类用于模拟Spring的配置文件
@Configuration
public class ShiroConfig {

    /**
     * 配置一个SecurityManager 安全管理器
     * @return
     */
    @Bean
    public SecurityManager securityManager(Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(realm);
        return  defaultWebSecurityManager;
    }
    // 配置一个自定义的Realm的bean,最终将使用这个bean返回的对象来完成我们的认证和授权
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm = new MyRealm();
        return  myRealm;
    }
    //配置一个Shiro的过滤器bean,这个bean将配置Shiro相关的一个规则的拦截
    //例如什么样的请求可以访问什么样的请求不可以访问等等
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        // 设置安全管理器
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/"); // 配置用户登录请求,如果需要进行登录时,shiro就会转到这个请求上,进入登录页面
        shiroFilterFactoryBean.setSuccessUrl("/success");// 配置成功之后转向的地址
        shiroFilterFactoryBean.setUnauthorizedUrl("/noPermission"); // 配置没有权限时转向的页面

        /**
         * 配置权限拦截规则
         *             anon:无需认证就可以访问
         *             logout:登出,清空内存
         *             authc:必须认证才可以访问
         *             user:必须拥有记住我功能才能用
         *             perms:拥有对某个资源的权限才能访问
         *             role:拥有某个角色权限才能访问
         */
        LinkedHashMap<String, String> filterChainMap = new LinkedHashMap<>();
        filterChainMap.put("/login","anon"); // 配置登录不需要认证
        filterChainMap.put("/logout","logout"); // 登出,清空当前用户内存,释放session对话
        filterChainMap.put("/admin/**","authc"); // admin开头的所有请求需要登录认证
        // 配置剩余的所有请求都需要进行登录认证,必须写在最后
        filterChainMap.put("/**","authc");
        // 设置权限拦截规则
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return  shiroFilterFactoryBean;
    }

}

– 定义MyRealm类


/**
 * 自定义的realm,用来实现用户的认证和授权
 * 父类 AuthorizingRealm  实现用户的认证(登录)和授权(权限)
 *
 */

public class MyRealm extends AuthorizingRealm {

    /**
     * 认证   这个方法不能手动调用shiro会自动调用
     * @param authenticationToken   用户身份  这里存放着用户的账号和密码
     * @return   用户登录成功后的身份证明
     * @throws AuthenticationException  如果认证失败shiro会抛出各种异常
     * 常用异常
     *  UnknownAccountException 账号不存在
     *  AccountException        账号异常
     *  LockedAccountException  账户锁定异常(冻结异常)
     *  IncorrectCredentialsException 密码认证失败以后Shiro自动抛出表示密码错误
     *  注意:
     *    如果这些异常不够用可以自定义异常类并继承Shiro认证异常父类AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();  // 获取页面中传递的用户账号
        String password = new String(token.getPassword()); //  获取页面中的用户密码实际工作中基本不需要获取
        System.out.println(username+"----"+password);
        /**
         * 认证账号,这里应该从数据库中获取数据
         * 如果进入if表示账号不存在要抛出异常
         */
        if (!"admin".equals(username)){
            throw  new UnknownAccountException();  // 抛出账号错误的异常
        }
        /**
         * 认证账号,这里应该从数据库中获取数据进行逻辑判断,判断账号是否可用
         * IP是否允许等等,根据不同的逻辑可以抛出不同的异常
         */
        if ("zhangsan".equals(username)){
            throw  new LockedAccountException();  // 抛出账号锁定的异常
        }
        // 创建密码认证对象,有shiro自动认证密码
        // 参数一:数据库中的账号(或页面账号)
        // 参数二:当前帐号的密码
        // 参数三:当前realm的名字
        // 若果密码认证成功则返回一个用户身份对象,如果密码认证失败shiro会抛出异常  IncorrectCredentialsException
        return new SimpleAuthenticationInfo(username,"123456",getName());
    }

– 定义Controller

package com.netft.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author: fengT
 * @date: 2020/7/27 0027 下午 21:01
 * @modified by
 */

@Controller
public class TestController {

    @RequestMapping("/")
    public String index(){
        return  "login";
    }

     @RequestMapping("/login")
    public String login(String username, String password, Model model){
        // 获取权限操作对象,利用这个对象来完成登录操作
        Subject subject = SecurityUtils.getSubject();
        //  用户是否登录过,进入if代表用户没有认证过需要进行认证
        if (!subject.isAuthenticated()){
            // 创建用户认证时的身份令牌,并设置我们从页面传递的账号和密码
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
            try {
                /**
                 * 指定登录,会自动调用我们Realm对象中的认证方法
                 * 如果登录失败就会抛出各种异常
                 */
            subject.login(usernamePasswordToken);
            }catch (UnknownAccountException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","账号错误!");
                return "login";
            }catch (LockedAccountException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","账号被锁定!");
                return "login";
            }catch (IncorrectCredentialsException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","密码错误");
                return "login";
            }catch (AuthenticationException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","认证失败!");
                return "login";
            }
        }
        return  "redirect:/success";
    }

    @RequestMapping("/logout")
    @ResponseBody
    public String logout(){
        return  "redirect:/";
    }


    @RequestMapping("/success")
    public String loginSuccess(){
        return  "success";
    }

    @RequestMapping("/noPermission")
    public String noPermission(){
        return  "noPermission";
    }

    @RequestMapping("/admin/test")
    @ResponseBody
    public String adminTest(){
        return  "/admin/test";
    }

    @RequestMapping("/user/test")
    @ResponseBody
    public String userTest(){
        return  "/user/test";
    }
}

–定义login.html,nopermission.html、success.html

// login.html
<form action="login" method="post">
    账号<input type="text" name="username"><br>
    密码<input type="text" name="password" id="password"><br>
    <input type="submit" value="登录" id="loginBut">
</form>
<span style="color: red" th:text="${errorMessage}"></span>
// nopermission.html
<h1>没有权限请联系管理员</h1>
// success.html
<h1>登录成功</h1>

到此测试。简单的shiro认证就做完了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值