SpringBoot整合Shiro:完成认证和授权小demo

SpringBoot整合Shiro:完成认证授权

1.技术SpringBoot+Mybatis+Maven+Shiro+Mysql

1.1:创建SpringBoot项目 当前我没有网络 所以是手动创建maven 可以去搜一下如何 自动创建SpringBoot项目

2:把以下内容复制到pom.xml文件中

    <!--springboot基础的创建-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <smybatis.version>2.1.0</smybatis.version>
    </properties>

    <dependencies>
        <!--SpringBook所需的jar包 默认不需要写版本号 继承父类的版本号-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </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>
        <!--springboot整合mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${smybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>RELEASE</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
        <!--上传文件的-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!--添加shiro安全框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--shiro自定义配置需要的插件-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>
        <!--shiro-spring整合-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--shiro缓存-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!--shiro和Thyemy整合  可以使用shiro的标签-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <!--实现SpringBoot热部署配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

    </dependencies>

    <!--spirng 打包成war包-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <includeEmptyDirectories>true</includeEmptyDirectories>
                </configuration>
            </plugin>
        </plugins>
    </build>

3:然后我们在项目中创建这几个文件夹 至这几个文件夹干什么我都不细说了

在这里插入图片描述

4:在application.yml配置文件配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 1234
    url: jdbc:mysql://127.0.0.1:3306/books?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true

entity:

package com.example.springboot.entity;

import javax.persistence.Entity;
import javax.persistence.Table;

@Table(name = "userinfo")
public class UserInfo {

    private Integer userid;
    private String username;
    private String userpassword;
    private String salt;
    private Integer hashinteration;

    @Override
    public String toString() {
        return "UserInfo{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", userpassword='" + userpassword + '\'' +
                ", salt='" + salt + '\'' +
                ", hashinteration=" + hashinteration +
                '}';
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUserpassword() {
        return userpassword;
    }

    public void setUserpassword(String userpassword) {
        this.userpassword = userpassword;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public Integer getHashinteration() {
        return hashinteration;
    }

    public void setHashinteration(Integer hashinteration) {
        this.hashinteration = hashinteration;
    }
}

dao层:

package com.example.springboot.dao;

import com.example.springboot.entity.UserInfo;
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;

public interface UserInfoDAO extends Mapper<UserInfo> {

    //根据用户输入的用户名到数据库进行查询
    @Select("select *from userinfo where username=#{param1}")
    UserInfo FindByUname(String username);

    //获取当前用户的角色
    @Select("select roleName from roleinfo where uid in(select userid from userinfo where username=#{param1})")
    List<String> findRole(String username);

    //根据角色名称获取当前的权限
    @Select("select jurname from jurinfo where rid in (select roleid from roleinfo where rolename=#{param1})")
    List<String> findJure(String roleName);
}

service层:

package com.example.springboot.service;

import com.example.springboot.dao.UserInfoDAO;
import com.example.springboot.entity.UserInfo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserInfoService {

    @Resource
    UserInfoDAO userInfoDAO;

    //在数据库用md5插入一条加密的密码
    public int InsertUserInfo(UserInfo userInfo)
    {
        userInfo.setSalt("csdn");
        userInfo.setHashinteration(5);
        return userInfoDAO.insert(userInfo);
    }

    //登录
    public UserInfo findUserName(String username)
    {
        return userInfoDAO.FindByUname(username);
    }

    //根据当前用户获取角色
    public List<String> findRole(String username)
    {
        return userInfoDAO.findRole(username);
    }
    //根据当前角色名称获取对应的权限
    public List<String> findJure(String roleName)
    {
        return userInfoDAO.findJure(roleName);
    }

}

shiro层:一个shiroconfig 一个myreamle
1: shiroconfig

package com.example.springboot.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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;

@Configuration
public class ShiroConfig {

    //添加Shiro内置过滤器
    /**
     * Shiro内置过滤器,可以实现权限相关的拦截器
     *    常用的过滤器:
     *       anon: 无需认证(登录)可以访问
     *       authc: 必须认证才可以访问
     *       user: 如果使用rememberMe的功能可以直接访问
     *       perms: 该资源必须得到资源权限才可以访问
     *       role: 该资源必须得到角色权限才可以访问
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //LinkedHashMap 有顺序的存 取出来的也是按顺序取

        LinkedHashMap<String, String> map = new LinkedHashMap<>();

        //登录提交不需要认证
        map.put("/login_submit","anon");
        //static下面的静态资源不需要拦截
        map.put("/static/**","authc");
        //设置要登录的页面
        shiroFilterFactoryBean.setLoginUrl("/login_show");
        //其他页面都要认证
        map.put("/*/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm)
    {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myRealm);
        return defaultWebSecurityManager;
    }

    /**
     * 自定义Realm
     * @return
     */
    @Bean(name = "myRealm")
    public MyRealm myRealm(@Qualifier("CredentialsMatcher") HashedCredentialsMatcher credentialsMatcher)
    {
        MyRealm myRealm=new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }

    /**
     * 设置加密对象,加密规则
     */
    @Bean(name = "CredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher()
    {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //使用md5加密
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //加密次数
        hashedCredentialsMatcher.setHashIterations(5);
        return hashedCredentialsMatcher;
    }
    /**
     *  配置ShiroDialect,用于thymeleaf和shiro标签配合使用
     */
    @Bean
    public ShiroDialect shiroDialect()
    {
        return new ShiroDialect();
    }
}

2:myreamle

package com.example.springboot.shiro;

import com.example.springboot.entity.UserInfo;
import com.example.springboot.service.UserInfoService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    UserInfoService userInfoService;

    /**
     *
     * @param principalCollection
     * @return   进行授权操作
     */

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //防止报错 加一个Try catch
        try{
            UserInfo userInfo = (UserInfo) principalCollection.getPrimaryPrincipal();
            //根据当前用户查询数据库角色
            List<String> role = userInfoService.findRole(userInfo.getUsername());
            if(role.size()!=0)
            {
                //创建一个Set把角色存起来
                Set<String> roles=new HashSet<>();
                for(String r:role)
                {
                    roles.add(r);
                }
                SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
                //根据角色分配权限
                //定义一个列表用来放权限
                ArrayList<String>  permissions = new ArrayList<>();
                for (String op:roles)
                {
                    //根据用户的角色来查询对应的权限
                    List<String> jure = userInfoService.findJure(op);
                    if(jure.size()!=0)
                    {
                        for (String j:jure)
                        {
                            permissions.add(j);
                        }
                    }
                }
                simpleAuthorizationInfo.addStringPermissions(permissions);
                return simpleAuthorizationInfo;
            }


        }catch (Exception e)
        {
            System.out.println("出错了");
        }
        return null;
    }

    /**
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException   进行认证操作
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户登录的用户名
        String principal = authenticationToken.getPrincipal().toString();
        UserInfo user = userInfoService.findUserName(principal);
        if(user==null)
        {
            return null;
        }
        //获取数据库的盐值
        ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
        return new SimpleAuthenticationInfo(user,user.getUserpassword(),bytes,getName());
    }
}

util层:

package com.example.springboot.util;

import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;

public class Md5Util {

    public static String getMd5Util(String pwd, String salt)
    {
        //加密方式
        String method="md5";
        //盐值
        ByteSource bytes = ByteSource.Util.bytes(salt);
        //加密次数
        int hashinteration=5;
        return new SimpleHash(method,pwd,bytes,hashinteration).toString();
    }

}

Controller层:

package com.example.springboot.controller;

import com.example.springboot.service.UserInfoService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserInfoController {

    @Autowired
    UserInfoService userInfoService;

    //显示登录页面
    @RequestMapping("login_show")
    public String login_show()
    {
        return "Login";
    }

    //登录提交
    @RequestMapping("login_submit")
    public String login_submit(String username,String userpassword,Model model)
    {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,userpassword);

        try{
            subject.login(token);
        //这里我就不抛出逐个错误了 这里可以通过抛出的异常来判断用户到底输错了什么
        }catch (Exception e){
            model.addAttribute("msg","账号密码错误");
            return "redirect:login_show";
        }
        return "redirect:login_success";
    }

    //登录成功页面
    @RequestMapping("login_success")
    public String login_success()
    {
        return "Success";
    }

    //退出
    @RequestMapping("login_out")
    public String login_out()
    {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        //重定向到现实登录页面
        return "redirect:login_show";
    }


}

resources–>templates–> 两个html网页 一个登录网页 一个登录成功网页
1:login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<form method="post" action="/login_submit">

    <table border="1px solid red" align="center">
        <tr>
            <td>用户名</td>
            <td>
                <input type="text" name="username"/>
            </td>
        </tr>
        <tr>
            <td>密码</td>
            <td>
                <input type="text" name="userpassword"/>
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="submit" value="提交"/>
            </td>
        </tr>
    </table>

</form>

</body>
</html>

2:success.html

<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--我们在这看看张三有没有emp:add权限-->
<!--这里我们可以看到可以显示添加用户 我们输入一个没有没有这个权限的 -->
<h2>登录成功了 <a href="/login_out">退出当前账户</a>

    <!--shiro判断角色权限 用三种可以自行百度细看-->

    <a shiro:hasPermission="emp:add">添加用户</a>
    <a shiro:hasPermission="emp:del">删除用户</a>
</h2>



</body>
</html>

Mysql数据:


#用户表
create table userinfo
(
 userid int primary key  auto_increment, --用户主键Id 自增
 username varchar(100),                  --用户名
 userpassword varchar(100),              --密码 
 salt varchar(100),                      --md5加密码的 盐值
 hashinteration int                      --我们通过Md5来加密的次数
)

insert into userinfo()

#角色表
create table roleinfo
(
	roleid int primary key auto_increment,  --角色主键Id 自增
	roleName varchar(100),                  --角色名称 
	uid int references userinfo(userid)     --用户表外键,因为一个用户可以有多个角色
)

#权限表
create table jurinfo
(
	jurId int primary key auto_increment, --主键Id 自增
	jurName varchar(100),                 --权限名称 例如 emp:add
	rid int references roleinfo(roleid)   --角色的外键 
)

--我们在数据库给张三配置几个角色 和权限

--超级管理员 有二个权限
--管理员 有1个权限
--人事经理没有权限  
insert into roleinfo(rolename,uid)values('超级管理员',1);
insert into roleinfo(rolename,uid)values('管理员',1);
insert into roleinfo(rolename,uid)values('人事经理',1);

insert into jurinfo(jurname,rid)values('emp:add',1);
insert into jurinfo(jurname,rid)values('emp:update',1);
insert into jurinfo(jurname,rid) values('dept:add',2);

结尾:我是一个新来博客的小白 欢迎大佬来指点错误

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往日时光--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值