Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)

目录Shiro简介Shiro快速入门SpringBoot-Shiro整合(最后会附上完整代码)附上最后的完整代码Shiro整合mybatis认证搞完了,我们再来看看授权Shiro-thymeleaf整合

Shiro简介

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理 三个核心组件:Subject, SecurityManager 和 Realms Subject代表了当前用户的安全操作 SecurityManager管理所有用户的安全操作,是Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。 Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。 Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

Shiro快速入门

导入依赖

        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-core</artifactId>            <version>1.7.1</version>        </dependency>        <!-- configure logging -->        <!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>jcl-over-slf4j</artifactId>            <version>2.0.0-alpha1</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>            <version>2.0.0-alpha1</version>        </dependency>        <dependency>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>            <version>1.2.17</version>        </dependency>

配置log4j.properties

log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache librarieslog4j.logger.org.apache=WARN# Springlog4j.logger.org.springframework=WARN# Default Shiro logginglog4j.logger.org.apache.shiro=INFO# Disable verbose logginglog4j.logger.org.apache.shiro.util.ThreadContext=WARNlog4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

配置Shiro.ini(在IDEA中需要导入ini插件)

[users]# user 'root' with password 'secret' and the 'admin' roleroot = secret, admin# user 'guest' with the password 'guest' and the 'guest' roleguest = guest, guest# user 'presidentskroob' with password '12345' ("That's the same combination on# my luggage!!!" ;)), and role 'president'presidentskroob = 12345, president# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'darkhelmet = ludicrousspeed, darklord, schwartz# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'lonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------# Roles with assigned permissions## Each line conforms to the format defined in the# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc# -----------------------------------------------------------------------------[roles]# 'admin' role has all permissions, indicated by the wildcard '*'admin = *# The 'schwartz' role can do anything (*) with any lightsaber:schwartz = lightsaber:*# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with# license plate 'eagle5' (instance specific id)goodguy = winnebago:drive:eagle5

快速入门实现类 quickStart.java

import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.text.IniRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class quickStart {    private static final transient Logger log = LoggerFactory.getLogger(quickStart.class);    /*        Shiro三大对象:                Subject: 用户                SecurityManager:管理所有用户                Realm: 连接数据     */    public static void main(String[] args) {        // 创建带有配置的Shiro SecurityManager的最简单方法        // realms, users, roles and permissions 是使用简单的INI配置。        // 我们将使用可以提取.ini文件的工厂来完成此操作,        // 返回一个SecurityManager实例:        // 在类路径的根目录下使用shiro.ini文件        // (file:和url:前缀分别从文件和url加载):        //Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");        //SecurityManager securityManager = factory.getInstance();        DefaultSecurityManager securityManager = new DefaultSecurityManager();        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");        securityManager.setRealm(iniRealm);        // 对于这个简单的示例快速入门,请使SecurityManager        // 可作为JVM单例访问。大多数应用程序都不会这样做        // 而是依靠其容器配置或web.xml进行        // webapps。这超出了此简单快速入门的范围,因此        // 我们只做最低限度的工作,这样您就可以继续感受事物.        SecurityUtils.setSecurityManager(securityManager);        // 现在已经建立了一个简单的Shiro环境,让我们看看您可以做什么:        // 获取当前用户对象 Subject        Subject currentUser = SecurityUtils.getSubject();        // 使用Session做一些事情(不需要Web或EJB容器!!!        Session session = currentUser.getSession();//通过当前用户拿到Session        session.setAttribute("someKey", "aValue");        String value = (String) session.getAttribute("someKey");        if (value.equals("aValue")) {            log.info("Retrieved the correct value! [" + value + "]");        }        // 判断当前用户是否被认证        if (!currentUser.isAuthenticated()) {            //token : 令牌,没有获取,随机            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");            token.setRememberMe(true); // 设置记住我            try {                currentUser.login(token);//执行登陆操作            } catch (UnknownAccountException uae) {//打印出  用户名                log.info("There is no user with username of " + token.getPrincipal());            } catch (IncorrectCredentialsException ice) {//打印出 密码                log.info("Password for account " + token.getPrincipal() + " was incorrect!");            } catch (LockedAccountException lae) {                log.info("The account for username " + token.getPrincipal() + " is locked.  " +                        "Please contact your administrator to unlock it.");            }            // ... 在此处捕获更多异常(也许是针对您的应用程序的自定义异常?            catch (AuthenticationException ae) {                //unexpected condition?  error?            }        }        //say who they are:        //print their identifying principal (in this case, a username):        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");        //test a role:        if (currentUser.hasRole("schwartz")) {            log.info("May the Schwartz be with you!");        } else {            log.info("Hello, mere mortal.");        }        //test a typed permission (not instance-level)        if (currentUser.isPermitted("lightsaber:wield")) {            log.info("You may use a lightsaber ring.  Use it wisely.");        } else {            log.info("Sorry, lightsaber rings are for schwartz masters only.");        }        //a (very powerful) Instance Level permission:        if (currentUser.isPermitted("winnebago:drive:eagle5")) {            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +                    "Here are the keys - have fun!");        } else {            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");        }        //all done - log out!        currentUser.logout();//注销        System.exit(0);//退出    }}

启动测试

SpringBoot-Shiro整合(最后会附上完整代码)

前期工作

导入shiro-spring整合包依赖

<!--  shiro-spring整合包 --><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.7.1</version></dependency>

跳转的页面index.html

<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>首页</title></head><body><h1>首页</h1><p th:text="${msg}"></p><a th:href="@{/user/add}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >add</a>| <a th:href="@{/user/update}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >update</a></body></html>

add.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>add</title></head><body><p>add</p></body></html>

update.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>update</title></head><body><p>update</p></body></html>

编写shiro的配置类ShiroConfig.java

package com.example.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;import java.util.Map;@Configurationpublic class ShiroConfig {    //3. ShiroFilterFactoryBean    @Bean    public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();        //设置安全管理器        factoryBean.setSecurityManager(defaultWebSecurityManager);        return factoryBean;    }    //2.创建DefaultWebSecurityManager    @Bean(name = "SecurityManager")    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){        DefaultWebSecurityManager SecurityManager=new DefaultWebSecurityManager();        //3.关联Realm        SecurityManager.setRealm(userRealm);        return SecurityManager;    }    //1.创建Realm对象    @Bean(name = "userRealm")    public UserRealm userRealm(){        return new UserRealm();    }}

编写UserRealm.java

package com.example.config;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;public class UserRealm extends AuthorizingRealm {    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        return null;    }    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        return null;    }}

编写controller测试环境是否搭建好

package com.example.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class MyController {    @RequestMapping({"/","/index"})    public String index(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";    }}

实现登录拦截

在ShiroConfig.java文件中添加拦截

Map<String,String> filterMap = new LinkedHashMap<>();        //对/user/*下的文件只有拥有authc权限的才能访问        filterMap.put("/user/*","authc");        //将Map存放到ShiroFilterFactoryBean中        factoryBean.setFilterChainDefinitionMap(filterMap);

这样,代码跑起来,你点击add或者update就会出现404错误,这时候,我们再继续添加,让它跳转到我们自定义的登录页

添加登录拦截到登录页

        //需进行权限认证时跳转到toLogin        factoryBean.setLoginUrl("/toLogin");        //权限认证失败时跳转到unauthorized        factoryBean.setUnauthorizedUrl("/unauthorized");

login.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>登录</title></head><body><form action="">    用户名:<input type="text" name="username"><br>    密码:<input type="text" name="password"><br>    <input type="submit"></form></body></html>

视图跳转添加一个login页面跳转

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

上面,我们已经成功拦截了,现在我们来实现用户认证

首先,我们需要一个登录页面

login.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>登录</title></head><body><p th:text="${msg}" style="color: red"></p><form th:action="@{/login}">    用户名:<input type="text" name="username"><br>    密码:<input type="text" name="password"><br>    <input type="submit"></form></body></html>

其次,去controller编写跳转到登录页面

    @RequestMapping("/login")    public String login(String username,String password,Model model){        //获得当前的用户        Subject subject = SecurityUtils.getSubject();        //封装用户数据        UsernamePasswordToken taken = new UsernamePasswordToken(username,password);        try{//执行登陆操作,没有发生异常就说明登陆成功            subject.login(taken);            return "index";        }catch (UnknownAccountException e){            model.addAttribute("msg","用户名错误");            return "login";        }catch (IncorrectCredentialsException e){            model.addAttribute("msg","密码错误");            return "login";        }    }

最后去UserRealm.java配置认证

   //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        String name = "root";        String password = "123456";        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;        if (!userToken.getUsername().equals(name)){            return null;//抛出异常  用户名错误那个异常        }        //密码认证,shiro自己做        return new SimpleAuthenticationInfo("",password,"");    }

运行测试,成功!!!

附上最后的完整代码

pom.xml引入的依赖

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 https://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.4.4</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <groupId>com.example</groupId>    <artifactId>springboot-08-shiro</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>springboot-08-shiro</name>    <description>Demo project for Spring Boot</description>    <properties>        <java.version>1.8</java.version>    </properties>    <dependencies>        <!--  shiro-spring整合包 -->        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-spring</artifactId>            <version>1.7.1</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-thymeleaf</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>        </plugins>    </build></project>

静态资源

index.html

<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>首页</title></head><body><h1>首页</h1><p th:text="${msg}"></p><a th:href="@{/user/add}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >add</a>| <a th:href="@{/user/update}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >update</a></body></html>

login.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>登录</title></head><body><p th:text="${msg}" style="color: red"></p><form th:action="@{/login}">    用户名:<input type="text" name="username"><br>    密码:<input type="text" name="password"><br>    <input type="submit"></form></body></html>

add.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>add</title></head><body><p>add</p></body></html>

update.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>update</title></head><body><p>update</p></body></html>

controller层

MyController.java

package com.example.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.UnknownAccountException;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;@Controllerpublic class MyController {    @RequestMapping({"/","/index"})    public String index(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 taken = new UsernamePasswordToken(username,password);        try{//执行登陆操作,没有发生异常就说明登陆成功            subject.login(taken);            return "index";        }catch (UnknownAccountException e){            model.addAttribute("msg","用户名错误");            return "login";        }catch (IncorrectCredentialsException e){            model.addAttribute("msg","密码错误");            return "login";        }    }}

config文件

ShiroConfig.java

package com.example.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;import java.util.Map;@Configurationpublic class ShiroConfig {    //4. ShiroFilterFactoryBean    @Bean    public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();        //5. 设置安全管理器        factoryBean.setSecurityManager(defaultWebSecurityManager);        /*  shiro内置过滤器            anon无需授权、登录就可以访问,所有人可访。            authc 需要登录授权才能访问。            authcBasicBasic HTTP身份验证拦截器            logout退出拦截器。退出成功后,会 redirect到设置的/URI            noSessionCreation不创建会话连接器            perms授权拦截器,拥有对某个资源的权限才可访问            port端口拦截器            restrest风格拦截器            roles角色拦截器,拥有某个角色的权限才可访问            sslssl拦截器。通过https协议才能通过            user用户拦截器,需要有remember me功能方可使用         */        Map<String,String> filterMap = new LinkedHashMap<>();        //对/user/*下的文件只有拥有authc权限的才能访问        filterMap.put("/user/*","authc");        //将Map存放到ShiroFilterFactoryBean中        factoryBean.setFilterChainDefinitionMap(filterMap);        //需进行权限认证时跳转到toLogin        factoryBean.setLoginUrl("/toLogin");        //权限认证失败时跳转到unauthorized        factoryBean.setUnauthorizedUrl("/unauthorized");        return factoryBean;    }    //2.创建DefaultWebSecurityManager    @Bean(name = "SecurityManager")    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){        DefaultWebSecurityManager SecurityManager=new DefaultWebSecurityManager();        //3.关联Realm        SecurityManager.setRealm(userRealm);        return SecurityManager;    }    //1.创建Realm对象    @Bean(name = "userRealm")    public UserRealm userRealm(){        return new UserRealm();    }}

UserRealm.java

package com.example.config;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;public class UserRealm extends AuthorizingRealm {    //授权    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        return null;    }    //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        String name = "root";        String password = "123456";        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;        if (!userToken.getUsername().equals(name)){            return null;//抛出异常  用户名错误那个异常        }        //密码认证,shiro自己做        return new SimpleAuthenticationInfo("",password,"");    }}

但是,我们在用户认证这里,真实情况是从数据库中取的,所以,我们接下来去实现一下从数据库中取出数据来实现用户认证

Shiro整合mybatis

前期工作

在前面导入的依赖中,继续添加以下依赖

        <!--  mysql      -->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>        </dependency>        <!--   log4j     -->        <dependency>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>            <version>1.2.17</version>        </dependency>        <!--  数据源Druid      -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid</artifactId>            <version>1.2.5</version>        </dependency>        <!--   引入mybatis     -->        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>2.1.4</version>        </dependency>        <!--  lombok      -->        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>

导入了mybatis和Druid,就去application.properties配置一下和DruidDruid

spring:  datasource:    username: root    password: 123456    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 # 自定义数据源    #Spring Boot 默认是不注入这些属性值的,需要自己绑定    #druid 数据源专有配置    initialSize: 5    minIdle: 5    maxActive: 20    maxWait: 60000    timeBetweenEvictionRunsMillis: 60000    minEvictableIdleTimeMillis: 300000    validationQuery: SELECT 1 FROM DUAL    testWhileIdle: true    testOnBorrow: false    testOnReturn: false    poolPreparedStatements: true    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j    filters: stat,wall,log4j    maxPoolPreparedStatementPerConnectionSize: 20    useGlobalDataSourceStat: true    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

mybatis

mybatis:  type-aliases-package: com.example.pojo  mapper-locations: classpath:mapper/*.xml

连接数据库编写实体类

package com.example.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructorpublic class User {        private Integer id;        private String name;        private String pwd;}

编写mapper

package com.example.mapper;import com.example.pojo.User;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;@Repository@Mapperpublic interface UserMapper {    public User getUserByName(String name);}

编写mapper.xml

<?xml version="1.0" encoding="UTF8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mapper.UserMapper">    <select id="getUserByName" parameterType="String" resultType="User">        select * from mybatis.user where name=#{name}    </select></mapper>

编写service

package com.example.service;import com.example.pojo.User;public interface UserService {    public User getUserByName(String name);}
package com.example.service;import com.example.mapper.UserMapper;import com.example.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl implements UserService{    @Autowired    UserMapper userMapper;    @Override    public User getUserByName(String name) {        return userMapper.getUserByName(name);    }}

使用数据库中的数据

修改UserRealm.java即可

package com.example.config;import com.example.pojo.User;import com.example.service.UserService;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;public class UserRealm extends AuthorizingRealm {    @Autowired    UserService userService;    //授权    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        return null;    }    //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;        //连接真实的数据库        User user = userService.getUserByName(userToken.getUsername());        if (user==null){            return null;//抛出异常  用户名错误那个异常        }        //密码认证,shiro自己做        return new SimpleAuthenticationInfo("",user.getPwd(),"");    }}

认证搞完了,我们再来看看授权

在ShiroConfig.java文件加入授权,加入这行代码: filterMap.put(“/user/add”,”perms[user:add]”);//只有拥有user:add权限的人才能访问add,注意授权的位置在认证前面,不然授权会认证不了;

运行测试:add页面无法访问

授权同理:filterMap.put(“/user/update”,”perms[user:update]”);//只有拥有user:update权限的人才能访问update

自定义一个未授权跳转页面

在ShiroConfig.java文件设置未授权时跳转到unauthorized页面,加入这行代码:factoryBean.setUnauthorizedUrl(“/unauthorized”); 2. 去Mycontroller写跳转未授权页面

    @RequestMapping("/unauthorized")    @ResponseBody//懒得写界面,返回一个字符串    public String unauthorized(){        return "没有授权,无法访问";    }

运行效果:

从数据库中接受用户的权限,进行判断

在数据库中添加一个属性perms,相应的实体类也要修改

修改UserRealm.java

package com.example.config;import com.example.pojo.User;import com.example.service.UserService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;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.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;public class UserRealm extends AuthorizingRealm {    @Autowired    UserService userService;    //授权    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //没有使用数据库,直接自己设置的用户权限,给每个人都设置了,现实中要从数据库中取        //info.addStringPermission("user:add");        //从数据库中得到权限信息        //获得当前登录的对象        Subject subject = SecurityUtils.getSubject();        //拿到User对象,通过getPrincipal()获得        User currentUser = (User) subject.getPrincipal();        //设置当前用户的权限        info.addStringPermission(currentUser.getPerms());        return info;    }    //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;        //连接真实的数据库        User user = userService.getUserByName(userToken.getUsername());        if (user==null){            return null;//抛出异常  用户名错误那个异常        }        //密码认证,shiro自己做        return new SimpleAuthenticationInfo(user,user.getPwd(),"");    }}

有了授权后,就又出现了一个问题,我们是不是要让用户没有权限的东西,就看不见呢?这时候,就出现了Shiro-thymeleaf整合

Shiro-thymeleaf整合

导入整合的依赖

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro --><dependency>   <groupId>com.github.theborakompanioni</groupId>    <artifactId>thymeleaf-extras-shiro</artifactId>    <version>2.0.0</version></dependency>

在ShiroConfig整合ShiroDialect

    //整合ShiroDialect: 用来整合 shiro thymeleaf    @Bean    public ShiroDialect getShiroDialect(){        return  new ShiroDialect();    }

修改index页面

<html lang="en" xmlns:th="http://www.thymeleaf.org"      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"><!-- 三个命名空间xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/extras/spring-security"xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"--><head>    <meta charset="UTF-8">    <title>首页</title></head><body><h1>首页</h1><p th:text="${msg}"></p><!--判断是否有用户登录,如果有就不显示登录按钮--><div th:if="${session.loginUser==null}">    <a th:href="@{/toLogin}" rel="external nofollow" >登录</a></div><div shiro:hasPermission="user:add">    <a th:href="@{/user/add}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >add</a></div><div shiro:hasPermission="user:update">    <a th:href="@{/user/update}" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >update</a></div></body></html>

判断是否有用户登录

   //这个是整合shiro和thymeleaf用到的,让登录按钮消失的判断        Subject subject = SecurityUtils.getSubject();        Session session = subject.getSession();        session.setAttribute("loginUser", user);

测试

以上就是Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)的详细内容,更多关于Java安全框架——Shiro的资料请关注其它相关文章!

你曾经说,你曾经说。走在爱的旅途,我们的脚步多么轻松……

Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)

相关文章:

你感兴趣的文章:

标签云: