springboot整合shiro
   
    
     中国加油,武汉加油!
    
   
    
    
    篇幅较长,配合右边目录观看
   
    
    
    项目准备
   
- 
创建springboot项目nz1904-springboot-07-shiro 
 
   
- 
导shiro相关依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
- 
application.properties配置模板引擎 # 配置模板引擎 spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 spring.thymeleaf.encoding=utf-8 spring.thymeleaf.cache=false
- 
修改主启动类 
 
   
    
    
    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 测试
   
- localhost/toIndex 跳转到login页面,因为被拦截了。
- 输入jiekami和123 跳转到index页面
- 输入其他数据会回到login页面并且报错
- 
     项目结构图
 
   
    
    
    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 版权协议,转载请附上原文出处链接和本声明。
