Shiro整合ssm

Shiro整合ssm

步骤

1. 创建一个拥有web框架支持的maven项目。

在这里插入图片描述

2. 准备数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission`  (
  `perid` int(0) NOT NULL AUTO_INCREMENT,
  `pername` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `percode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1, '查询用户信息', 'user:query');
INSERT INTO `permission` VALUES (2, '修改用户', 'user:update');
INSERT INTO `permission` VALUES (3, '删除用户', 'user:delete');
INSERT INTO `permission` VALUES (4, '添加用户', 'user:insert');
INSERT INTO `permission` VALUES (5, '导出用户', 'user:export');

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (
  `roleid` int(0) NOT NULL AUTO_INCREMENT,
  `rolename` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '仓管管理员');
INSERT INTO `role` VALUES (2, 'CEO');
INSERT INTO `role` VALUES (3, '保安');

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission`  (
  `perid` int(0) NOT NULL,
  `roleid` int(0) NOT NULL,
  PRIMARY KEY (`perid`, `roleid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES (1, 1);
INSERT INTO `role_permission` VALUES (1, 2);
INSERT INTO `role_permission` VALUES (1, 3);
INSERT INTO `role_permission` VALUES (2, 1);
INSERT INTO `role_permission` VALUES (2, 2);
INSERT INTO `role_permission` VALUES (3, 1);
INSERT INTO `role_permission` VALUES (3, 2);
INSERT INTO `role_permission` VALUES (4, 1);
INSERT INTO `role_permission` VALUES (5, 3);

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `userid` int(0) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `userpwd` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `salt` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan', '4b05a8716a430f71c6911d2e9149092f', '男', '武汉', '07f63bbf285e4719bfee1cc2bb81db33');
INSERT INTO `user` VALUES (2, 'lisi', '99cc11855b41ff3e5f7c0af3c5090a8c', '女', '北京', '2d7e37f019144764ac02aa7220929f93');
INSERT INTO `user` VALUES (3, 'wangwu', '6d70c027801af4dc892ab340d4bf73b6', '女', '成都', '99f6bf1b540145699e6e5c90480105b0');

-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role`  (
  `userid` int(0) NOT NULL,
  `roleid` int(0) NOT NULL,
  PRIMARY KEY (`userid`, `roleid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (2, 2);
INSERT INTO `user_role` VALUES (3, 3);

SET FOREIGN_KEY_CHECKS = 1;

3. 添加所需依赖

 <dependencies>
<!--    shiro整合spring依赖-->
    <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-spring</artifactId>
          <version>1.7.0</version>
      </dependency>
<!--shiro和redis整合的依赖-->
      <dependency>
          <groupId>org.crazycake</groupId>
          <artifactId>shiro-redis</artifactId>
          <version>2.4.6</version>
      </dependency>
<!--    druid依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.8</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
<!--    mysql-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>
<!--    spring相关依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>
<!--    mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version>
    </dependency>
<!--    lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.26</version>
    </dependency>
<!--    jsp servlet-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
      </dependency>
<!--      fastjson-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>2.0.25</version>
      </dependency>
  </dependencies>

4. 配置文件

4.1 resources下的 spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--1.包扫描-->
    <context:component-scan base-package="com.ly"/>
    <!--2.注解驱动-->
    <mvc:annotation-driven/>
    <!--3.静态资源放行-->
    <mvc:default-servlet-handler/>
    <!--4.视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--5.数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName"
                  value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:3306/shrio?serverTimezone=Asia/Shanghai"/>
    </bean>
    <!--6.SqlSessionFactory 加载mybatis的配置-->
    <bean id="sessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource"
                  ref="dataSource"/>
        <!--映射文件所在的路径-->
        <property name="mapperLocations"
                  value="classpath:mapper/*.xml"/>
    </bean>
    <!--7.设置dao接口的代理实现类-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName"
                  value="sessionFactory"/>
        <!--dao接口所在的包-->
        <property name="basePackage"
                  value="com.ly.mapper"/>
    </bean>
    <!--8.事务管理-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"
                  ref="dataSource"/>
    </bean>
    <!--9.开启事务的注解驱动-->
    <tx:annotation-driven/>
</beans>
4.2 WEB-INF下的web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--配置前端控制器-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring.xml</param-value>
    </init-param>
    <!--tomcat启动时加载该类-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
4.3 修改spring.xml
    <!--shiro和spring整合的配置-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
        <!--设置缓存管理器-->
<!--        <property name="cacheManager" ref="redisCacheManager"/>-->
    </bean>

    <!--redis缓存管理器-->
    <bean id="redisCacheManager" class="org.crazycake.shiro.RedisCacheManager">
        <!--缓存管理的地址redisManager-->
<!--        <property name="redisManager" ref="redisManager"/>-->
    </bean>

    <!--redis管理器-->
<!--    <bean id="redisManager" class="org.crazycake.shiro.RedisManager">-->
<!--        <property name="host" value="192.168.121.110"/>-->
<!--        <property name="database" value="1"/>-->
<!--        <property name="port" value="6379"/>-->
<!--    </bean>-->

    <bean id="myRealm" class="com.ly.realm.MyRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
    </bean>

    <!--加密器-->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="MD5"/>
        <property name="hashIterations" value="1024"/>
    </bean>

    <!--shiro过滤器 id:必须和web.xml里面的过滤器配置的名称对应-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--未登录时跳转的路径-->
        <property name="loginUrl" value="/unlogin"/>
        <!--过滤规则-->
        <property name="filterChainDefinitions">
            <value>
                /login=anon
                /**=authc
            </value>
        </property>
        <!--引入自定义过滤器-->
        <property name="filters">
            <map>
                <entry key="authc" value-ref="myFilter"/>
            </map>
        </property>
    </bean>
    <!-- 启动Shrio的注解 shiro加在controller应该属于springmvc的配置 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor" />
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!--自定义过滤器-->
    <bean id="myFilter" class="com.ly.filter.LoginFilter"/>
4.4修改web.xml

注意顺序,filter标签级别高,servlet标签前面。

	<!--shiro的过滤器:必须和ShiroFilterFactoryBean的id一致-->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

5. 登陆页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆页面</title>
</head>
<body>
    <form action="/login" method="post">
        账号:<input type="text" name="username"/><br><br>
        密码:<input type="text" name="password"/><br><br>
        <input type="submit" value="登录"/>
    </form>
</body>
</html>

6. 对照数据库,创建dao、service、controller及相关文件

在这里插入图片描述

7. 整合认证和授权

7.1 编写MyRealm
public class MyRealm extends AuthorizingRealm {
	@Autowired
    private UserService userService;
    @Autowired
    private PermissionService permissionService;

    /**
     * @Description: <认证业务>
     * @param[1] authenticationToken
     * @return AuthenticationInfo
     * @Author: MrLiu-柳
     * @Date: 2023/7/10 20:11
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1.获取登陆账号
        String username = token.getPrincipal().toString();
        //2.根据账号去获取去用户信息
        User user = userService.selectByUsername(username);
        if (user != null) {
            //3.获取用户信息中的盐
            ByteSource salt = ByteSource.Util.bytes(user.getSalt());
            /*
            * 这段代码是在进行用户身份验证时使用的 SimpleAuthenticationInfo 对象的构造方法。下面是对每个参数的理解:
               - user:表示用户对象,包含了用户名以及其他相关的用户信息。
               - user.getUserpwd():表示用户的密码,这里使用了 user 对象提供的方法来获取密码。
               - salt:表示密码的盐值,用于增加密码的安全性。盐值是一个随机生成的字符串,会与密码进行混合加密。
               - this.getName():表示当前调用该方法的对象的名称,可能是表示当前的领域、模块或者其他的标识。
               总的来说,该代码段的作用是创建一个包含用户身份认证信息的对象,用于在后续的身份验证过程中进行比对和判断。其中,密码会被加密并且加入盐值增加安全性。
            * */
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName());
            return info;
        }
        return null;
    }

    /**
     * @Description: <授权业务>
     * @param[1] principalCollection
     * @return AuthorizationInfo
     * @Author: MrLiu-柳
     * @Date: 2023/7/10 20:11
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) {
        //1.获取当前登陆者账号信息
        User user = (User) collection.getPrimaryPrincipal();
        //2.根据id获取账号拥有的权限
        List<String> permission = permissionService.findPermissionByUserid(user.getUserid());
        if (permission.size() != 0) {
            //3.创建一个 SimpleAuthorizationInfo 对象用于保存权限信息
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //4.将权限信息添加到SimpleAuthorizationInfo对象中
            info.addStringPermissions(permission);
            return info;
        }
        return null;
    }
}

其他:
dao层:

接口:
	User selectByUsername(String username);
	
	List<Permission> findPermissionByUserid(Integer userid);
	
映射文件:
	<select id="selectByUsername" resultType="com.ly.pojo.User">
       	 select * from user where username = #{username}
	 </select>
	 
	<select id="findPermissionByUserid" resultType="com.ly.pojo.Permission">
        select p.* from user_role ur
                            join role_permission rp
                                 on ur.roleid = rp.roleid
                            join permission p
                                 on rp.perid = p.perid
        where ur.userid = #{userId}
    </select> 

service层:

接口:
User selectByUsername(String username);

List<String> findPermissionByUserid(Integer userid);

实现类:
	@Override
    public User selectByUsername(String username) {
        return dao.selectByUsername(username);
    }

	@Override
    public List<String> findPermissionByUserid(Integer userid) {
        List<Permission> permissionList= dao.findPermissionByUserid(userid);
        List<String> collect = permissionList.stream().map(item -> item.getPercode()).collect(Collectors.toList());
        return collect;
    }

8. 补充

8.1 Result类(utils包下)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;
    private String msg;
    private Object data;
}
8.2 LoginFilter类(filter包下)
public class LoginFilter extends FormAuthenticationFilter {
    /**
     * @Param: [javax.servlet.ServletRequest, javax.servlet.ServletResponse]
     * @return: boolean
     * @Author: MrLiu-柳
     * @Date: 2023/7/7 15:09
     * @Role:
     *  - 未登录访问资源时,会触发该方法。
     *  ---默认内容是重定向到登录页面---重写改为返回json数据
     */
    @Override
    protected boolean onAccessDenied(ServletRequest req, ServletResponse resp) throws Exception {
        //解决响应数据的中文乱码问题
        resp.setContentType("application/json;charset=utf-8");
        Result result = new Result(401, "请先登录", null);
        //把java对象转化为json字符串
        String jsonString = JSON.toJSONString(result);
        PrintWriter writer = resp.getWriter();
        writer.println(jsonString);
        writer.flush();
        writer.close();
        return false;
    }
}
8.3 MyHandler类(handler包下)
@ControllerAdvice //处理controller中出现的异常,该类注解必须能被spring扫描到
public class MyHandler {

    /**
     * @Author: MrLiu
     * @Date: 2023/7/7 10:48
     * @Param: [e]
     * @return: [org.apache.shiro.authz.UnauthorizedException]
     * @Role:
     *   - 处理UnauthorizedException未经授权的异常
     */
    @ExceptionHandler(value = UnauthorizedException.class)//捕获异常
    @ResponseBody
    public Result unauthorizedException(UnauthorizedException e){
        e.printStackTrace();
        return new Result(403, "权限不足", null);
    }
}

8.4 unlogin.jsp&&403.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
请先登录
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
权限不足
</body>
</html>

9. controller层

LoginController

@Controller
@ResponseBody
public class LoginController {
    /**
     * @Description: <认证授权业务>
     * @param[1] loginVo
     * @return String
     * @Author: MrLiu-柳
     * @Date: 2023/7/10 17:28
     */
    @PostMapping("/login")
    public String login(LoginVo loginVo){//@RequestBody接受的json对象参数。  不加:表单数据以及地址栏传递的数据
        //传递的数据校验
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(loginVo.getUsername(), loginVo.getUserpwd());
        try {
            subject.login(token);
            return "success"; //经过视图解析器 /WEB-INF/views/success.jsp
        }catch (Exception e){
            e.printStackTrace();
            return "redirect:/login.jsp";
        }
    }

    /**
     * @Description: <未登录提示>
     * @return Result
     * @Author: MrLiu-柳
     * @Date: 2023/7/10 20:53
     */
    @GetMapping("/unlogin")
    public Result unlogin(){
        return new Result(401,"请先登录",null);
    }
}

userController

@RestController
public class UserController {
    @GetMapping("/query")
    @RequiresPermissions(value = "user:query")
    public String query(){
        return "user:query------------------------";
    }

    @GetMapping("/update")
    @RequiresPermissions(value = "user:update")
    public String update(){
        return "user:update------------------------";
    }

    @GetMapping("/delete")
    @RequiresPermissions(value = "user:delete")
    public String delete(){
        return "user:delete------------------------";
    }

    @GetMapping("/insert")
    @RequiresPermissions(value = "user:insert")
    public String insert(){
        return "user:insert------------------------";
    }

    @GetMapping("/export")
    @RequiresPermissions(value = "user:export") //该注解不能别识别
    public String export(){
        return "user:export------------------------";
    }
}

10. PostMain测试

为该项目配置tomcat并运行,在postmain中测试接口。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如有错误请及时联系本人,以便纠错!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值