springboot实战--shiro安全框架的使用--thymeleaf--mybatis

标签: springboot  shiro

 

shiro安全框架:

两大核心功能:认证,授权

需求描述

有三个用户,root ,blog ,user

root拥有所有权限,blog只能进入blog ,user只能进入user

登录页面

前台登录界面,输入正确的用户名密码可以进入首页。

密码错误

用户不存在

 

首页

首页root登录效果。拥有操作博客,用户的权限。

 

blog用户登录:只能看到有权限的页面入口

 

需求实现:

1.表数据建立

/**
四个表
user role Permission
user_role  role_permession
user和role是多对多的关系
role和permission也是多对多关系
*/ 

/**
四个表
user role Permission
user_role  role_permession
user和role是多对多的关系
role和permission也是多对多关系
*/ 
---用户
CREATE TABLE USER(
userId INT PRIMARY KEY AUTO_INCREMENT ,
userName VARCHAR(32) ,
PASSWORD VARCHAR(64)
)ENGINE INNODB DEFAULT CHARSET=utf8;

   ---角色
    CREATE TABLE role(
    roleId INT PRIMARY KEY AUTO_INCREMENT ,
    roleName VARCHAR(32) 
    )ENGINE INNODB DEFAULT CHARSET=utf8;    
 --权限   
CREATE TABLE Permission(
    pId INT PRIMARY KEY AUTO_INCREMENT ,
    pName VARCHAR(32)

    )ENGINE INNODB DEFAULT CHARSET=utf8; 
 --用户角色对应
CREATE TABLE user_role(
    urId INT,
    userId INT ,
    roleId INT 
)ENGINE INNODB DEFAULT CHARSET=utf8; 
---角色权限对应关系表   
CREATE TABLE role_permession(
    rpId INT,
    pId INT ,
    roleId INT 
)ENGINE INNODB DEFAULT CHARSET=utf8; 
    
    
---添加用户 
INSERT INTO USER (username,PASSWORD) VALUES('root','1');
 ---添加外键
 ALTER TABLE user_role ADD
 CONSTRAINT FK_user_id FOREIGN KEY(userId)  REFERENCES USER(userId) ON DELETE NO ACTION ON UPDATE NO ACTION 
  ---添加外键 
 ALTER TABLE user_role ADD
 CONSTRAINT FK_role_id FOREIGN KEY(roleId)  REFERENCES role(roleId) ON DELETE NO ACTION ON UPDATE NO ACTION 
 
--INSERT 预置数据 permission
INSERT INTO `permission` (`pId`, `pName`) VALUES('1','/admin/**');
INSERT INTO `permission` (`pId`, `pName`) VALUES('2','/user/**');
INSERT INTO `permission` (`pId`, `pName`) VALUES('3','/blog/**');

---role
INSERT INTO `role` (`roleId`, `roleName`) VALUES('1','admin');
INSERT INTO `role` (`roleId`, `roleName`) VALUES('2','user');
INSERT INTO `role` (`roleId`, `roleName`) VALUES('3','blog');
--user_role
INSERT INTO `user_role` (`urId`, `userId`, `roleId`) VALUES('1','1','1');
INSERT INTO `user_role` (`urId`, `userId`, `roleId`) VALUES('2','1','2');
INSERT INTO `user_role` (`urId`, `userId`, `roleId`) VALUES('3','2','2');
INSERT INTO `user_role` (`urId`, `userId`, `roleId`) VALUES('4','3','3');
INSERT INTO `user_role` (`urId`, `userId`, `roleId`) VALUES('4','1','3');
--role_permession
INSERT INTO `role_permession` (`rpId`, `pId`, `roleId`) VALUES('1','1','1');
INSERT INTO `role_permession` (`rpId`, `pId`, `roleId`) VALUES('2','2','2');
INSERT INTO `role_permession` (`rpId`, `pId`, `roleId`) VALUES('3','3','3'); 
 
 ----根据USER NAME 查询 
 SELECT *
 FROM USER u, role r, user_role ur, role_permession rp , permission p
 WHERE u.userName = 'blog'
 AND u.userId = ur.userId
 AND ur.roleId = r.roleId
 AND r.roleId = rp.roleId
 AND rp.pId = p.pId;

maven依赖

<?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.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang</groupId>
    <artifactId>shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.2</version>
        </dependency>


<!--        shiro 整合 thymeleaf-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

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

</project>

 

 实体类

User

package com.wang.pojo;

import java.util.ArrayList;
import java.util.HashSet;

public class User {
    private int userId;
    private String userName;
    private String password;
    private ArrayList<Role> roles;

    public int getUserId() {
        return userId;
    }

    public User() {
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public ArrayList<Role> getRoles() {
        return roles;
    }

    public void setRoles(ArrayList<Role> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", roles=" + roles +
                '}';
    }

    public User(int userId, String userName, String password, ArrayList<Role> roles) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
        this.roles = roles;
    }
}

Permission

package com.wang.pojo;

import java.util.HashSet;

public class Permission {
    private int pId;
    private String pName;
    public Permission() {
    }
    public Permission(int pId, String pName) {
        this.pId = pId;
        this.pName = pName;
    }
    public int getpId() {
        return pId;
    }
    public void setpId(int pId) {
        this.pId = pId;
    }
    public String getpName() {
        return pName;
    }
    public void setpName(String pName) {
        this.pName = pName;
    }
    @Override
    public String toString() {
        return "Permission{" +
                "pId=" + pId +
                ", pName='" + pName + '\'' +
                '}';
    }
}

Role

 

package com.wang.pojo;

import java.util.ArrayList;

public class Role  {
    private int roleId;
    private String roleName;
    //一对多
    private ArrayList<Permission> permissions;

    public int getRoleId() {
        return roleId;
    }

    public Role() {
    }

    public void setRoleId(int roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public ArrayList<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(ArrayList<Permission> permissions) {
        this.permissions = permissions;
    }

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                ", permissions=" + permissions +
                '}';
    }

    public Role(int roleId, String roleName, ArrayList<Permission> permissions) {
        this.roleId = roleId;
        this.roleName = roleName;
        this.permissions = permissions;
    }
}

 mapper 接口mapper文件

只需要一个UserMapper 

package com.wang.mapper;

import com.wang.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface UserMapper {

    User queryUserByName(String userName);
}

 UserMapper.xml

一个用户肯能有不同的角色,角色有不同的权限。使用多对多查询用户的所有角色和权限。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wang.mapper.UserMapper">
    
<!--    多对多查询-->
    <select id="queryUserByName" resultMap="userResultMap">
        select u.userId as uId,u.userName as uName,u.password as password ,
                r.roleId as rId,r.roleName as roleName,
               p.pId as pId,p.pName as pName
        from user u, role r, user_role ur, role_permession rp , permission p
        where u.userName = #{userName}
        and u.userId = ur.userId
        and ur.roleId = r.roleId
        and r.roleId = rp.roleId
        and rp.pId = p.pId
    </select>
    <resultMap id="userResultMap"   type="user">
        <result property="userId" column="uId"></result>
        <result property="userName" column="uName"></result>
        <result property="password" column="password"></result>
        <collection property="roles"  javaType="list" ofType="Role" >
            <result property="roleName" column="roleName"></result>
            <result column="roleId" property="roleName"></result>
            <collection property="permissions"   ofType="Permission" javaType="list">
                <result property="pId" column="pId"></result>
                <result property="pName" column="pName"></result>
            </collection>
        </collection>
    </resultMap>
</mapper>

UserService  &UserServiceImpl

 

 

package com.wang.service;

import com.wang.mapper.UserMapper;
import com.wang.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public User queryUserByName(String userName) {
        return userMapper.queryUserByName(userName);
    }
}


package com.wang.service;

import com.wang.pojo.User;

public interface UserService {
    User queryUserByName(String userName);
}

 Realm 编写

两大核心:认证和授权

package com.wang.service;

import com.wang.pojo.Permission;
import com.wang.pojo.Role;
import com.wang.pojo.User;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;


public class MyRealm extends AuthorizingRealm {

    Logger log = LoggerFactory.getLogger(MyRealm.class);
    @Autowired
    private UserServiceImpl userService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("==>doGetAuthorizationInfo2222");
        SimpleAuthorizationInfo simpleAuthorizationInfo =new SimpleAuthorizationInfo();
//        拿到当前登录对象  认证成功之后传递过来的
        User userInfo = (User) principalCollection.getPrimaryPrincipal();
        log.debug("测试日志------是否生效");
        //从数据库获得角色和权限信息
        for (Role role :userInfo.getRoles()) {
            simpleAuthorizationInfo.addRole(role.getRoleName());
            for (Permission permission : role.getPermissions()) {
                simpleAuthorizationInfo.addStringPermission(permission.getpName());
            }
        }
        return simpleAuthorizationInfo;
    }


    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1.从主体传过来的认证信息中,获得用户名
        System.out.println("==>doGetAuthenticationInfo1111");
        String userName = (String) authenticationToken.getPrincipal();

        // 2.通过用户名到数据库中获取凭证
        User  user = userService.queryUserByName(userName);
//        如果数据库没有查询到则用户不存在
        if (user == null) {
            return null;
        }
        //同时密码验证也会做,密码错误则会抛出
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                user, // 用户名//给后序授权的地方传递
                user.getPassword(), // 密码
                null,//盐值
                getName() // realm name
        );
        return simpleAuthenticationInfo;
    }
}

ShiroConfig

过滤器注册

注入比要的安全组件  Realm  DefaultWebSecurityManager  ShiroFilterFactoryBean

package com.wang.config;


import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.wang.service.MyRealm;
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.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //ShiroFilterBean

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(manager);

        /*
         *anon 无需认证
         * authc 必须认证
         * user 必须有记住我才能使用
         * perms 拥有对某个资源的权限才能访问
         * role 用户某个角色权限
         */
        //拦截
        Map<String ,String> filterMap = new LinkedHashMap<>();
        filterMap.put("/user/*","anon");
        filterMap.put("/blog/*","authc");
        //拥有权限/user/**  才能访问/user/*
        filterMap.put("/user/*","perms[/user/**]");
        filterMap.put("/blog/*","perms[/blog/**]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        shiroFilterFactoryBean.setLoginUrl("/");
        return  shiroFilterFactoryBean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myRealm);
        return defaultWebSecurityManager;
    }
    //创建realm 对象
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return  myRealm;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(1);

        return  hashedCredentialsMatcher;
    }


//    整合thymeleaf  shiro

    @Bean
    public ShiroDialect shiroDialect(){
        return  new ShiroDialect();
    }
}

 WebMvcConfig

视图定制

package com.wang.config;


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //page url 指定视图名称,由于templates下面的静态资源不能直接访问
        registry.addViewController("/main.html").setViewName("main");
        registry.addViewController("/blog/blog.html").setViewName("/blog/blog");
        registry.addViewController("/user/user.html").setViewName("/user/user");
    }
}

 

controller

package com.wang.controller;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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 UserController {

//    前台登录功能实现
    @RequestMapping("/login")
    public String  trsactionLogin(String username, String password, Model model){

//        获取登录用户对象
        Subject subject = SecurityUtils.getSubject();
        //登录令牌
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
        try {
//            登录认证开始
            subject.login(usernamePasswordToken);
            //此处做了一个重定向
            return "redirect:/main.html";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","用户名不存在");
            return "index";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "index";
        }
    }
}

 

 

前台页面

首页,登录功能

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>登录一下</h2>
<h4 th:text="${msg}" style="color: red"></h4>
<form th:action="@{/login}" method="post">
    用户名:<input type="text" name="username">
    密码:<input type="password" name = "password">
    <input type="submit" value="登录" />
</form>
</body>
</html>

登录之后的主页

main.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
您好:

<a shiro:hasPermission="/blog/**" th:href="@{blog/blog.html}">博客管理</a>
<a shiro:hasPermission="/user/**" th:href="@{/user/user.html}">用户管理</a>
</body>
</html>

blog/blog.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2 >欢迎进入博客管理页面</h2>
</body>
</html>

user/user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>欢迎进入用户管理页面</h2>
</body>
</html>

配置文件

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/ssmbuild?useUnicode=true&serverTimezone=UTC&characterchaset=utf8
    password: 1111
    username: root
    driver-class-name: com.mysql.cj.jdbc.Driver

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

 

 

 

版权声明:本文为qq_32527287原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_32527287/article/details/105527165