springboot+mybatis整合shiro

参考了b站的springboot视频。
1、shiro简介
它是阿帕奇的java安全框架。包含了三个主要对象:subject(当前用户)、SecurityManager(安全管理)、Realm(数据相关)。
在这里插入图片描述
Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。其基本功能点如下图所示:
在这里插入图片描述
shiro详细介绍
2、demo结构:
在这里插入图片描述
3、使用了springboot、mybatis、druid etc,实现登录控制,用户认证、请求授权(本文没有实现授权)等。
4、首先搭建环境:
java配置类Shiroconfig和自定义的Realm对象:UserRealm。它们之间的联系建立再Realm这个对象上。
Shiroconfig:(可以配置登录拦截和授权)

package com.example.shiro_pht.config;

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 {
    //shiro的三大对象:suject securityManager realm

    //shiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getsfb(@Qualifier("getdsm") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //1、实现登录拦截
        //添加shiro的内置过滤器
        /*
        anon:无需认证就能访问
        authc:必须认证
        user:必须拥有remember me功能才能
        perms:拥有某个资源的权限才能使用
        role:拥有角色权限才能访问

        必须用到setFilterChainDefinitionMap,设置过滤器链,打开其源码,其参数为一个map,用于添加
         */
        Map<String, String> filterChainDefinitionMap=new LinkedHashMap<>();

        //权限操作(顺序要注意)
        //filterChainDefinitionMap.put("/userpage/add","perms[userpage:add]"); //只有带了user:add的用户才有权限访问
        //filterChainDefinitionMap.put("/userpage/update","perms[userpage:update]");

        //登录认证拦截
        filterChainDefinitionMap.put("/userpage/add","anon"); //这个路径无需认证
        filterChainDefinitionMap.put("/userpage/*","authc"); //即这个路径必须认证,否则跳转到错误页面
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        //如果没有权限则跳转到一个页面(这里我们跳转到登录页面)
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        //跳转到未授权页面
        //shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");

        return shiroFilterFactoryBean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getdsm(@Qualifier("realms") UserRealm userRealm){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //关联realm
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }

    //realm对象,使用自定义的realm类对象
    @Bean
    public UserRealm realms(){
        return new UserRealm();
    }
}

自定义Realm对象,UserRealm(认证部分连接了service层,获取数据库中的用户名和密码),其中的token,它与Hellocontroller中的token是互通的(在框架环境下),直接调用:

package com.example.shiro_pht.config;

import com.example.shiro_pht.Pojo.User;
import com.example.shiro_pht.service.Userservice;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

//自定义realm,继承AuthorizingRealm即可
public class UserRealm extends AuthorizingRealm {

    @Autowired
    Userservice userservice;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权操作!");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证操作!");
        //upt即token,它与Hellocontroller中的token是互通的,直接调用!!!
        //这里很重要!!!
        UsernamePasswordToken upt=(UsernamePasswordToken)authenticationToken;
        //连接数据库

        User user=userservice.queryuser(upt.getUsername());

        System.out.println(upt);
        System.out.println(upt.getUsername());
        if(user==null){
            return null; //抛出错误
        }
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
}

5、Controller层:

package com.example.shiro_pht.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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Hellocontroller {
    @RequestMapping({"/", "/index"})
    public String hello(Model model) {
        model.addAttribute("msg", "hello");
        return "index";
    }

    @RequestMapping("/userpage/add")
    public String add() {
        return "userpage/add";
    }

    @RequestMapping("/userpage/update")
    public String update() {
        return "userpage/update";
    }

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

    @RequestMapping("/login")
    public String login(@RequestParam("name") String name,@RequestParam("password") String password, Model model) {
        System.out.println(name);
        System.out.println(password);

        //使用shiro获取当前用户
        Subject userNow = SecurityUtils.getSubject();
        //获取令牌
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);

        try {
            //执行登录的方法,这步封装很复杂
            userNow.login(token);
            return "index";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg", "用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }

    /*
    @RequestMapping("/noauth")
    @ResponseBody
    public String unauth(){
        return "没有权限";
    }
    */
}

6、mapper层,Usermapper:

package com.example.shiro_pht.mapper;

import com.example.shiro_pht.Pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface Usermapper {
    public User queryuser(String name);
}

7、实体类:

package com.example.shiro_pht.Pojo;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private String password;
}

8、由于功能简单,service层接口与mapper层方法相同,实现类Userserviceimp:

package com.example.shiro_pht.service;

import com.example.shiro_pht.Pojo.User;
import com.example.shiro_pht.mapper.Usermapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Userserviceimp implements Userservice{
    @Autowired
    Usermapper usermapper;
    @Override
    public User queryuser(String name) {
        User user=usermapper.queryuser(name);
        return user;
    }
}

9、resources:
mapper.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.example.shiro_pht.mapper.Usermapper">
    <select id="queryuser" resultType="user">
        select * from accountlist where name=#{name}
    </select>
</mapper>

index.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<p th:text="${msg}"></p>
This is the first page!
<a href="/userpage/add">add</a><br>
<a href="/userpage/update">update</a>
</body>
</html>

login.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>登录页面</h1>
<p th:text="${msg}" style="color:#f60202"></p>
<form th:action="@{/login}">
    username:<input type="text" name="name"><br>
    password:<input type="text" name="password"><br>
    <input type="submit" value="submit">
    <input type="reset" value="reset">
</form>
</body>
</html>

application.yaml:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/majinbuu1?serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 500

    filters: stat,wall,log4j
    maxPoolPreparedAtatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: durid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.shiro_pht.Pojo

add.html与update.html略。就一句body。
10、实验报错与结果:
报错:
1、org.apache.shiro.authc.UsernamePasswordToken - null报错:
通过打印输出测试,最终发现错误为前端传值的名字和后端接收时不匹配。(username----->name)
2、授权页面无法跳转,按照网上的说法,调整了Shiroconfig中授权和拦截的顺序,仍然不行,貌似授权页面无法跳转,因为是懒加载blabla,未解决…

结果:
数据库中的所有账户密码都能登录,且正确的实现了拦截、认证等。
这只是个入门级别的demo,记录下学习过程,以后有机会再深入学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个框架整合可以分为以下几个步骤: 1. 集成 Spring Boot:在 pom.xml 文件中添加 Spring Boot 依赖,创建 Spring Boot 启动类。 2. 集成 MyBatis Plus:在 pom.xml 文件中添加 MyBatis Plus 依赖,配置数据源和 MyBatis Plus 相关配置。 3. 集成 Shiro:在 pom.xml 文件中添加 Shiro 依赖,创建 Shiro 配置类,配置 Shiro 的 Realm 和 SecurityManager。 4. 集成 JWT:在 pom.xml 文件中添加 jjwt 依赖,创建 JWT 工具类,用于生成和解析 JWT。 下面是一个简单的示例代码,你可以根据你的实际需求进行调整: 1. pom.xml 文件中添加依赖: ```xml <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!-- jjwt --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>${jjwt.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> ``` 2. 创建 Spring Boot 启动类: ```java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 3. 配置 MyBatis Plus: ```java @Configuration @MapperScan("com.example.mapper") public class MyBatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } } ``` 4. 配置 Shiro: ```java @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setUnauthorizedUrl("/401"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/401", "anon"); filterChainDefinitionMap.put("/**", "jwt"); shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("jwt", new JwtFilter()); shiroFilter.setFilters(filters); return shiroFilter; } @Bean public DefaultWebSecurityManager securityManager(Realm realm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); return securityManager; } @Bean public Realm realm() { return new UserRealm(); } } ``` 5. 创建 JWT 工具类: ```java public class JwtUtil { private static final String SECRET_KEY = "your_secret_key"; private static final long EXPIRATION_TIME = 3600_000; // 1 hour public static String generateToken(String username) { Date now = new Date(); Date expiration = new Date(now.getTime() + EXPIRATION_TIME); return Jwts.builder() .setSubject(username) .setIssuedAt(now) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String getUsernameFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); return claims.getSubject(); } public static boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (JwtException e) { return false; } } } ``` 6. 创建 JwtFilter: ```java public class JwtFilter extends AuthenticatingFilter { @Override protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) { HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("Authorization"); if (StringUtils.isBlank(token)) { return null; } return new JwtToken(token); } @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { HttpServletResponse response = (HttpServletResponse) servletResponse; response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期,请重新登录\"}"); return false; } @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("Authorization"); if (StringUtils.isBlank(token)) { return false; } return JwtUtil.validateToken(token); } } ``` 7. 创建 JwtToken: ```java public class JwtToken implements AuthenticationToken { private final String token; public JwtToken(String token) { this.token = token; } @Override public Object getPrincipal() { return JwtUtil.getUsernameFromToken(token); } @Override public Object getCredentials() { return token; } } ``` 8. 创建 UserRealm: ```java public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String username = (String) authenticationToken.getPrincipal(); User user = userService.getByUsername(username); if (user == null) { throw new UnknownAccountException("账号不存在"); } return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); } } ``` 这样,简单的 Spring Boot + Shiro + JWT + MyBatis Plus 整合就完成了。你可以根据具体的需求,对代码进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值