欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-17 17:47:29
shiro简介 apache shiro是一个强大且易用的java安全框架,执行身份验证、授权、密码和会话管理 三个核心组件:subject, securitymanager 和 real...

shiro简介

  1. apache shiro是一个强大且易用的java安全框架,执行身份验证、授权、密码和会话管理
  2. 三个核心组件:subject, securitymanager 和 realms
  3. subject代表了当前用户的安全操作
  4. securitymanager管理所有用户的安全操作,是shiro框架的核心,shiro通过securitymanager来管理内部组件实例,并通过它来提供安全管理的各种服务。
  5. realm充当了shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,shiro会从应用配置的realm中查找用户及其权限信息。
  6. 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, stdout

log4j.appender.stdout=org.apache.log4j.consoleappender
log4j.appender.stdout.layout=org.apache.log4j.patternlayout
log4j.appender.stdout.layout.conversionpattern=%d %p [%c] - %m %n

# general apache libraries
log4j.logger.org.apache=warn

# spring
log4j.logger.org.springframework=warn

# default shiro logging
log4j.logger.org.apache.shiro=info

# disable verbose logging
log4j.logger.org.apache.shiro.util.threadcontext=warn
log4j.logger.org.apache.shiro.cache.ehcache.ehcache=warn

配置shiro.ini(在idea中需要导入ini插件)

[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = 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);//退出
    }
}

启动测试

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

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;

@configuration
public 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;

@controller
public 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";
    }
}

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

实现登录拦截

在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;

@controller
public 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;

@configuration
public class shiroconfig {
    //4. shirofilterfactorybean
    @bean
    public shirofilterfactorybean getshirofilterfactorybean(@qualifier("securitymanager") defaultwebsecuritymanager defaultwebsecuritymanager){
        shirofilterfactorybean factorybean = new shirofilterfactorybean();
        //5. 设置安全管理器
        factorybean.setsecuritymanager(defaultwebsecuritymanager);

        /*  shiro内置过滤器
            anon	无需授权、登录就可以访问,所有人可访。
            authc	 需要登录授权才能访问。
            authcbasic	basic http身份验证拦截器
            logout	退出拦截器。退出成功后,会 redirect到设置的/uri
            nosessioncreation	不创建会话连接器
            perms	授权拦截器,拥有对某个资源的权限才可访问
            port	端口拦截器
            rest	rest风格拦截器
            roles	角色拦截器,拥有某个角色的权限才可访问
            ssl	ssl拦截器。通过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配置一下和druid
druid

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
@noargsconstructor
public 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
@mapper
public 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;

@service
public 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,注意授权的位置在认证前面,不然授权会认证不了;

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

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

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

授权同理: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 "没有授权,无法访问";
    }

运行效果:

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

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

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

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

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

修改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(),"");
    }
}

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

有了授权后,就又出现了一个问题,我们是不是要让用户没有权限的东西,就看不见呢?这时候,就出现了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的资料请关注其它相关文章!