springboot结合shiro入门学习(一)

其实关于shiro的博客介绍特别多,这里记录一下自己的学习过程。

简介

Shiro(希罗)的前身叫JSecurity项目,始于2003年,2008年加入Apache软件基金会并成为Apache顶级项目。

官网:http://shiro.apache.org/
github:https://github.com/apache/shiro
Shiro是一个强大而灵活的开源Java安全框架,提供了认证、授权、密码加密、会话管理等功能。

在这里插入图片描述
Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

核心概念:

Subject
Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

SecurityManager
SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。
SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。

Authenticator
Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

Authorizer
Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

realm
Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

sessionManager
sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

正题:

本篇主要是记录shiro认证。
在这里插入图片描述

项目的整体图:
在这里插入图片描述

首先我们需要在pom.xml加入shiro与spring整合依赖


 <!-- shiro与spring整合依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

整个pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com</groupId>
    <artifactId>example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>example</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- shiro与spring整合依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

首先介绍一下 Shiro内置过滤器,可以实现权限相关的拦截器。

配置缩写 对应的过滤器 功能
anon AnonymousFilter 指定url可以匿名访问
authc FormAuthenticationFilte 指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛
authcBasic BasicHttpAuthenticationFilter 指定url需要basic登录
logout LogoutFilter 登出过滤器,配置指定url就可以实现退出功能,非常方便
noSessionCreation NoSessionCreationFilte 需要指定权限才能访问
perms PermissionsAuthorizationFilter 指定url可以匿名访问
port PortFilter 需要指定端口才能访问
rest HttpMethodPermissionFilter 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释
roles RolesAuthorizationFilter 需要指定角色才能访问
user UserFilter 需要已登录或“记住我”的用户才能访问

接下来编写Shiro配置类(*)


 /**
 * Shiro的配置类
 * 
 *
 */
@Configuration
public class ShiroConfig {

    /**
     * 创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //添加Shiro内置过滤器
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *    常用的过滤器:
         *       anon: 无需认证(登录)可以访问
         *       authc: 必须认证才可以访问
         *       user: 如果使用rememberMe的功能可以直接访问
         *       perms: 该资源必须得到资源权限才可以访问
         *       role: 该资源必须得到角色权限才可以访问
         */
        Map<String,String> filterMap = new LinkedHashMap<String,String>();

        filterMap.put("/static/**", "anon");
        filterMap.put("/tologin", "anon");
        filterMap.put("/loginsubmit", "anon");
        filterMap.put("/registe", "anon");

        filterMap.put("/*", "authc");

        //修改调整的登录页面
        shiroFilterFactoryBean.setLoginUrl("/tologin");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);


        return shiroFilterFactoryBean;
    }

    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建Realm
     */
    @Bean(name="userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

其中要注意的是 filterMap.put("/*", “authc”);要放在最后,要不然全都给拦截了, filterMap.put("/loginsubmit", “anon”);提交请求也要 anon权限要不然提交不成功。
@bean标签不能遗漏。@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。

自定义Realm类

/**
 * 自定义Realm
 * 
 *
 */
public class UserRealm extends AuthorizingRealm{
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        System.out.println("执行授权逻辑");
        return null;
    }


    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        System.out.println("执行认证逻辑");

        //假设这是数据库获取的用户名和密码
        String name = "aa";
        String password = "123456";

        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken)arg0;
        if(!token.getUsername().equals(name)){
            //用户名不存在
            return null;//shiro底层会抛出UnKnowAccountException
        }

        //2.判断密码
        return new SimpleAuthenticationInfo("",password,"");
    }

}

编写Controller的登录逻辑

@Controller
public class UserController {
    @RequestMapping("/tologin")
    public String tologin(){
        return "login";
    }
    @RequestMapping("/towelcome")
    public String inwelcome(){
        return "welcome";
    }
    /**
     * 登录逻辑处理
     */
    @RequestMapping("/loginsubmit")
    public String login(String username,String password,Model model){
        /**
         * 使用Shiro编写认证操作
         */
        //1.获取Subject
        Subject subject = SecurityUtils.getSubject();

        //2.封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        //3.执行登录方法
        try {
            subject.login(token);

            //登录成功
            //跳转到test.html
            return "redirect:/towelcome";
        } catch (UnknownAccountException e) {
            //e.printStackTrace();
            //登录失败:用户名不存在
            model.addAttribute("msg", "用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e) {
            //e.printStackTrace();
            //登录失败:密码错误
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }

}


编写登录界面

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    <script type="text/javascript">
        function jump(){
            window.location.href="/registe";
        }
    </script>
</head>
<body style="background-image:url('static/image/loginback3.jpg');background-size:cover">


<div style="text-align:center;">
    <h1 style="text-shadow:0 0 10px;letter-spacing: 1px;text-align: center;color:blue ">Login</h1>
    <span style="color:red" th:text="${msg}"></span>
    <form action="loginsubmit" method="post">
        <input style="border-radius: 4px;width: 278px;height: 18px;margin-bottom: 10px;outline: none;padding: 10px;font-size: 13px;" type="text" required="required" placeholder="用户名" name="username">
        </input><br>
        <input style="border-radius: 4px;width: 278px;height: 18px;margin-bottom: 10px;outline: none;padding: 10px;font-size: 13px;" type="password" required="required" placeholder="密码" name="password">
        </input> <br>

        <button style="border-radius: 5px;" type="submit">登录</button>
        <button style="border-radius: 5px;" onclick="jump()">注册</button>
    </form>
</div>
</body>
</html>

效果图
在这里插入图片描述
出现问题:如果同一个用户有几个密码会出现500的错误
接下来下一篇是shiro结合mybatis数据库的整合。
源码地址:https://gitee.com/jzzhu123456/shiroHouse_asd
下一篇:springboot结合shiro入门学习(二)

发布了21 篇原创文章 · 获赞 9 · 访问量 4512

猜你喜欢

转载自blog.csdn.net/qq_36470898/article/details/97528132
今日推荐