SpringBoot-Shiro-MyBatis-MySql小练习(简单的验证和授权操作,附源码)

一、新建一个web项目:spring-shiro-02,创建项目时添加web支持,引入静态资源(页面,图片,css文件等)创建项目以后先简单测试项目能否运行,不要着急一开始急着写代码;新建一个Controller来跳转请求:

@Controller
public class MyController {
    @RequestMapping({"/","/index"})
    public String toIndex(){
        return "index";
    }
}

当然,index.html自己写的一个能够操作基本业务的简单页面啦,在浏览器输入Http:/localhost:8080或者是http://localhost:8080/index都可以进入index页面即可。初步成功,即可往后进行。

 二、然后在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.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-shiro-02</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-shiro-02</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-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>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.1</version>
        </dependency>
        <!-- thymeleaf-shiro整合,同时需要配置 -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- configure logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </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>
        <resources>     <!--过滤静态资源-->
            <resource>  
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>

三、引入html和css等静态资源(这里是自己写的,就不展示代码了,一个不能再简单的页面了,views下有三个级别,后面用来做权限用,拥有不同的权限的可以进入不同的页面)

 四、在resources下创建application.yaml文件,配置数据库连接以及关闭缓存,以便在测试环节中可以方便的更改界面(yml文件对格式要求很高,每一个空格代表一级目录,所以要严格对齐,否则报错)

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/db?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

    #关闭缓存
    thymeleaf:
      cache: false

 同样在resources下配置log4j的priperties文件(可以方便的从控制台监控到输出信息):

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

五、接下来就完成具体的代码了,包括以下内容:

1、先在数据库创建一个表,来存储相应的数据:并在IDEA中连接数据库(对应着用户名、密码和权限)

 CREATE TABLE USER (
id INT(12) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
pwd VARCHAR(20)
 );
 INSERT INTO USER(NAME,pwd)
 VALUES("root","123456"),("guster","123456"),("wanju","123456");
 
  SELECT * FROM USER;

 

在IDEA中就可以看到刚才新建的表啦~

2、创建相应的pojo实体类:(引入lombok的依赖以后可以利用注解自动生成有参无参构造和get/set方法)

package com.exer.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
    private String perms;
}

 3、mapper包下创建UserMapper接口,

package com.exer.mapper;

import com.exer.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface UserMapper {
    public User queryUserByName();//根据姓名查用户
}

 4、然后写相应的mapper配置: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.exer.mapper.UserMapper">
    <!--public User queryUserByName(String name);-->
    <select id="queryUserByName" parameterType="String" resultType="User">
        select * from db.user where name = #{name}
    </select>
</mapper>

5、service层有UserService接口和其实现类UserServiceImp:  (service层调用这里的mapper层)

package com.exer.service;
import com.exer.pojo.User;
public interface UserService {
    //根据姓名查用户
    public User queryUserByName(String name);
}
package com.exer.service;

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

@Service
public class UserServiceImp implements UserService{
    @Autowired
    UserMapper userMapper;

    @Override
    public User queryUserByName(String name) {
        return userMapper.queryUserByName(name);
    }
}

6、config层下将刚才配置的数据源加入到bean中:

package com.exer.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/*     将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
@Configuration
public class DruidConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
        return new DruidDataSource();
    }
}

7、想要和数据库建立连接实现查询,还得添加如下配置(application.properties文件添加即可):

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

8、编写MyController类,响应请求:

package com.exer.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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {

    @RequestMapping({"/","/index"})
    public String toIndex(){
        return "index";
    }
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }
    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){
        return "views/level1/"+id;
    }
    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){
        return "views/level2/"+id;
    }
    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id){
        return "views/level3/"+id;
    }
    @RequestMapping("/unAuth")
    @ResponseBody
    public String unAuthorize(){
        return "未经授权,禁止访问!";
    }
    @RequestMapping("/toLogout")
    public String logout(){
        return "redirect:/toLogin";
    }
    @RequestMapping("/login")
    public String login1(String username,String password, Model model){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try{
            subject.login(token);
            return "index";
        }catch(UnknownAccountException e){
            model.addAttribute("msg","用户名错误!");
            return "login";
        }catch(IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误!");
            return "login";
        }
    }
}

9、编写shiroConfig类,设置过滤器等

package com.exer.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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 {
    //1、ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("webSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(defaultWebSecurityManager);     //设置安全管理器
        //设置shiro内置过滤器,拦截请求 /*
        // anon:无需认证就可访问              authc:必须认证了才能访问
        // user:必须拥有记住我功能才能访问     perms:拥有对某个资源的权限才能访问
        // roles:拥有某个角色的权限才能访问* */
        Map<String, String> filter=new LinkedHashMap<>();
//        filter.put("/*/*","authc");
        filter.put("/level1/*","perms[low]");
        filter.put("/level2/*","perms[mid]");
        filter.put("/level3/*","perms[high]");      //授权
        filter.put("/toLogout","logout");             //发起/logout的请求,就会触发shiro的注销过滤器logout
        bean.setFilterChainDefinitionMap(filter);   //设置过滤器
        bean.setUnauthorizedUrl("/unAuth"); //设置未授权的请求
        bean.setLoginUrl("/toLogin");         //设置登录的请求
        return bean;
    }

    //2、DefaultWebSecurityManager
    @Bean(name = "webSecurityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getUserRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);//关联realm
        return securityManager;
    }

    //3、创建Realm,需要自定义Realm类
    @Bean
    public UserRealm getUserRealm(){
        return new UserRealm();
    }
    //整合shiroDialect:整合shiro和thymeleaf的配置在这里
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
}

10、编写Realm类,实现认证和授权部分

package com.exer.config;
import com.exer.pojo.User;
import com.exer.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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义Realm,并重写其方法
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("==================================");
        System.out.println("===========进入授权方法============");
        System.out.println("==================================");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();   //添加权限
        Subject currentSub = SecurityUtils.getSubject();    //获取当前用户
        User user1 = (User) currentSub.getPrincipal();      //从认证里面拿到的principal就是当前的user
        info.addStringPermission(user1.getPerms());
        return info;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("==================================");
        System.out.println("===========进入认证方法============");
        System.out.println("==================================");
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //链接数据库,获取用户信息
        User user = userService.queryUserByName(userToken.getUsername());
        if(user==null){
            return null;    //用户不存在时,返回UnKnownAccount的错误
        }
        //拿到当前用户供前端参考
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);
        //密码认证
        return new SimpleAuthenticationInfo(user,user.getPwd(),""); //第一个参数的user给当前subject的principal了
    }
}

大功告成,测试一下吧~

登录成功,右上角只显示注销和当前用户,并且该用户只能进去一部分页面,没有权限的页面无法进入;

注销以后,只显示登录按钮;

现存的问题:对于当前用户,没有权限的界面不应该显示出来,只显示有权限部分的页面。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值