springboot篇】十四. springboot整合shiro 上

  • Post author:
  • Post category:其他




springboot整合shiro


中国加油,武汉加油!



篇幅较长,配合右边目录观看



项目准备

  1. 创建springboot项目nz1904-springboot-07-shiro

    在这里插入图片描述

  2. 导shiro相关依赖

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.3.2</version>
    </dependency>
    
  3. application.properties配置模板引擎

    # 配置模板引擎
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    spring.thymeleaf.mode=HTML5
    spring.thymeleaf.encoding=utf-8
    spring.thymeleaf.cache=false
    
  4. 修改主启动类

    在这里插入图片描述



1. 案例(不连接数据库测试)



1.1 定义一个Shiro的配置类ShiroConfig

package com.wpj.config;

import com.wpj.realm.MyRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro整个配置文件
 */
@SpringBootConfiguration
public class ShiroConfig {

    private Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    // 配置过滤器,拦截请求
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        logger.info("shiroFilterFactoryBean。。。。。。。");
        // 认证失败跳转页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

        /**
         * logout: 登出过滤器
         * perms:权限控制
         * roles: 具有某一角色才能访问
         */
        Map<String, String> map = new LinkedHashMap<String, String>();

        map.put("/login", "anon"); // anon匿名过滤器,不认证也可以访问
        map.put("/**", "authc"); // authc认证过滤器:所有请求都必须在用户认证之后才能访问
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }


    // 配置安全管理器
    // securityManager必须要跟上面的过来securityManager名字一致
    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        logger.info("securityManager。。。。。。。");

        // 设置校验的Realm对象
        securityManager.setRealm(myRealm);

        return securityManager;
    }

    // 配置Realm
    // 名字同上
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm = new MyRealm();
        logger.info("myRealm。。。。。。。");

        return myRealm;
    }
}



1.2 定义一个MyRealm类

package com.wpj.realm;

import com.wpj.pojo.User;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * shiro跟数据库交互的桥梁
 */
public class MyRealm extends AuthorizingRealm {

    @Override
    public String getName() {
        return "MyRealm";
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取用户名
        String userName = (String) authenticationToken.getPrincipal();
        // 通过用户名查询用户对象

        // 查询出来(模拟数据库)
        if(!(userName.equals("jiekami"))){
            return null;
        }

        User user = new User(1,"jiekami","123");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getName(), user.getPwd(), getName());

        return simpleAuthenticationInfo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}



1.3 定义一个User对象,实现序列化

serialVersionUID 要自己生成

在这里插入图片描述

package com.wpj.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 8434196542261610760L;

    private Integer id;
    private String name;
    private String pwd;

}



1.4 新建主页和登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    this is index page!
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>

    <form action="/login" method="post">
        姓名: <input type="text" name="name" /><span th:text="${nameError}"></span><br />
        密码: <input type="text" name="pwd" /><span th:text="${pwdError}"></span><br />
        <span th:text="${otherError}"></span>
        <input type="submit" value="登录">
    </form>

</body>
</html>



1.5 定义一个Controller

package com.wpj.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

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

    @RequestMapping("/toIndex")
    public String toIndex(){
        return "index";
    }
    
 	@RequestMapping("/login")
    public String login(User user, Model model) {
        // 封装成请求对象
        UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPwd());
        // 获取登录的主题对象
        Subject subject = SecurityUtils.getSubject();
        try{
            // 登录
            subject.login(token);
        } catch (UnknownAccountException e) {
            logger.error("未知账户异常");
            model.addAttribute("nameError","未知账户异常");
            return "login";
        } catch (IncorrectCredentialsException e) {
            logger.error("密码错误");
            model.addAttribute("pwdError","密码错误");
            return "login";
        } catch (Exception e) {
            logger.error("其他问题登录失败" + e.fillInStackTrace());
            model.addAttribute("otherError","其他问题登录失败" + e.fillInStackTrace());
            return "login";
        }
        return "index";
    }
}



1.6 启动主启动类

因为没连接数据库,springboot自动配置了url,如果不排除自动配置的类DataSourceAutoConfiguration会报错。

package com.wpj;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}



1.7 测试

  1. localhost/toIndex 跳转到login页面,因为被拦截了。
  2. 输入jiekami和123 跳转到index页面
  3. 输入其他数据会回到login页面并且报错
  4. 项目结构图

    在这里插入图片描述



2. 功能扩展



2.1 退出功能



2.1.1 index.html添加退出按钮

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    this is index page!

    <a href="/logout">退出</a>

</body>
</html>



2.1.2 ShiroConfig配置 登出过滤器

	map.put("/logout", "logout");  // logout登出过滤器

在这里插入图片描述



2.2 密码散列



2.2.1 ShiroConfig配置密码散列

// 密码散列
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");   // MD5散列
        hashedCredentialsMatcher.setHashIterations(1);  // 散列次数
        return hashedCredentialsMatcher;
    }

在这里插入图片描述



2.2.2 修改MyRealm

User user = new User(1,"jiekami", "e99a18c428cb38d5f260853678922e03");
// 加盐
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
        user.getName(), user.getPwd(), ByteSource.Util.bytes("abc"), getName());



2.3 显示用户信息



2.3.1 修改Realm

SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                user, user.getPwd(), ByteSource.Util.bytes("abc"), getName());

在这里插入图片描述



2.3.2 修改Controller

// 获取第一个参数 --》  SimpleAuthenticationInfo(user, user.getPwd(), ByteSource.Util.bytes("abc"), getName());
        User user1 = (User)SecurityUtils.getSubject().getPrincipal();
        model.addAttribute("user", user1);

在这里插入图片描述



2.3.3. 修改index.Html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    欢迎<sapn th:text="${user.name}"></sapn>登录<br />
    this is index page!

    <a href="/logout">退出</a>

</body>
</html>



2.3.4 测试

在这里插入图片描述



版权声明:本文为TheNew_One原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。