shiro(入门二)shiro集成spring+mybatis+springMvc+Redis

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_42651904/article/details/88116078

1.准备工作

1.1准备所需要的依赖架包
<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
    </dependency>

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.3.2</version>
    </dependency>

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.41</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.0.29</version>
    </dependency>
    <!-- mybatis核心包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.1.0</version>
    </dependency>
    <!-- mybatis/spring包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.10</version>
    </dependency>



  </dependencies>
1.2 demo路径结构:

在这里插入图片描述

1.3 配置文件:

jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=123456
#定义初始连接数
initialSize=1
#定义最大连接数
maxActive=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.baidu.shiro" />

    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:spring/jdbc.properties" />
    </bean>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}"></property>
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${maxActive}"></property>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}"></property>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${maxWait}"></property>
    </bean>

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--以类名当别名 -->
        <property name="typeAliasesPackage" value="com/baidu/shiro/domain" />
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath*:com/baidu/shiro/mapping/*.xml"></property>
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com/baidu/shiro/dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>


    <!--securityManager:这个属性是必须的-->
    <!--loginUrl:没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,
    不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面-->
    <!--successUrl:登录成功默认跳转页面-->
    <!--unauthorizedUrl:没有权限默认跳转的页面-->
    <!--anon表示不要验证就可以访问-->
    <!--roles["admin"] 需要admin觉得才能访问-->
    <!--perms["user:delete"] 需要delete权限才能访问-->
    <!--authc:该过滤器下的页面必须验证后才能访问-->
   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="login.html" />
            <property name="unauthorizedUrl" value="403.html" />
            <property name="filterChainDefinitions">
                <value>
                    /login.html = anon
                    /subLogin = anon
                    /testRole = roles["admin"]
                    /testRole1 = roles["admin", "admin1"]
                    /testRole2 = rolesOr["admin", "admin1"]
                    /testPerms = perms["user:delete"]
                    /testPerms1 = perms["user:delete","user:update"]
                    /* = authc
                </value>

            </property>
   </bean>

    <!--创建SecurityManager对象-->
    <bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
       <property name="realm" ref="realm" />

    </bean>
    <!--创建自定义realm-->
    <bean class="com.baidu.shiro.realm.CustomRealm" id="realm">
        <property name="credentialsMatcher" ref="credentialsMatcher" />
    </bean>
    <!--设计加密方式为MD5,加密次数为1次-->
    <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher" id="credentialsMatcher">
        <property name="hashAlgorithmName" value="md5"/>
        <property name="hashIterations" value="1"/>
    </bean>
</beans>

配置注解都有详细介绍

springmvc:

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--扫描路径-->
    <context:component-scan base-package="com.baidu.shiro.controller"/>

    <mvc:annotation-driven/>
    <!-- 排除静态文件 -->
    <mvc:resources location="/" mapping="/*"/>

    <!-- 开启AOP -->
    <aop:config proxy-target-class="true"/>
    <!--管理bean的生命周期-->
    <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <!--权限注解的advisor -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
</beans>
1.4 数据库表字段:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.核心源代码:

自定义realm

package com.baidu.shiro.realm;

import com.baidu.shiro.domain.User;
import com.baidu.shiro.service.UserService;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CustomRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        // 从数据库或者缓存中获得角色数据
        Set<String> roles = getRolesByUserName(username);
        //获得权限数据
        Set<String> permissions = getPermissionsByUserName(username);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(permissions);
        simpleAuthorizationInfo.setRoles(roles);

        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 1.从主体传过来的认证信息中,获得用户名
        String username = (String) token.getPrincipal();

        // 2.通过用户名到数据库中获取凭证
        String password = getPasswordByUsername(username);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,
                password, "customRealm");
        //加盐
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(username));
        return simpleAuthenticationInfo;
    }

    //通过用户名获得密码
    private String getPasswordByUsername(String username) {
        User user = userService.getUserByUserName(username);
        return user.getPassword();
    }

    //通过用户名获得角色信息
    private Set<String> getRolesByUserName(String username) {
        List<String> roles = userService.getRolesByUserName(username);
        Set<String> sets = new HashSet<String>(roles);
        return sets;
    }
    //通过用户名获得权限信息
    private Set<String> getPermissionsByUserName(String username) {
        Set<String> sets = new HashSet<String>();
        sets.add("user:delete");
        sets.add("user:add");
        return sets;
    }

    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("123456", "Mark");
        System.out.println(md5Hash.toString());
    }
}

自定义拦截器:RolesOrFilter

package com.baidu.shiro.filter;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

/**
 * @Author: WH
 * @Date: 2019/3/4 10:23
 * @Version 1.0
 */
public class RolesOrFilter extends AuthorizationFilter {


    protected boolean isAccessAllowed(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response, Object mappedValue) throws Exception {
        Subject subject = getSubject(request, response);
        //获得角色
        String[] roles = (String[]) mappedValue;

        if (roles == null || roles.length == 0) {
            return  true;
        }
        for (String role : roles) {
            if (subject.hasRole(role)) {
                return  true;
            }
        }
        return  false;
    }
}

在spirng中加入如下配置

<!--创建自定义filter-->
    <bean class="com.baidu.shiro.filter.RolesOrFilter" id="rolesOrFilter" />
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="login.html" />
            <property name="unauthorizedUrl" value="403.html" />
            <property name="filterChainDefinitions">
                <value>
                    /login.html = anon
                    /subLogin = anon
                    /testRole1 = roles["admin", "admin1"]
                    /testRole2 = rolesOr["admin", "admin1"]
                    /testPerms = perms["user:delete"]
                    /testPerms1 = perms["user:delete","user:update"]
                    /* = authc
                </value>
            </property>
            <property name="filters">
                <util:map>
                    <entry key="rolesOr" value-ref="rolesOrFilter" />
                </util:map>
            </property>
   </bean>

controller:

package com.baidu.shiro.controller;

import com.baidu.shiro.domain.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
public class UserController {


    @RequestMapping(value = "/subLogin", method = RequestMethod.POST,produces = "application/json;charset=utf-8")
    @ResponseBody
    public String subLogin(User user) {
        System.out.println("aaa");
        Subject subject = SecurityUtils.getSubject();
        System.out.println("haha");
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());

        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            return e.getMessage();
        }
        if (subject.hasRole("admin")) {
            return  "有admin权限";
        }

        return "无admin权限";
    }
    //注解判断是否有admin角色,有注解就不用配置/testRole = roles["admin"]
    @RequiresRoles("admin")
    @ResponseBody
    @RequestMapping(value = "/testRole", method = RequestMethod.GET)
    public String testRole() {
        return "testRole success";
    }
	//注解判断是否有admin1角色,有注解就不用配置/testRole1 = roles["admin1"]
    @RequiresPermissions("admin1")
    @ResponseBody
    @RequestMapping(value = "/testRole1", method = RequestMethod.GET)
    public String testRole1() {
        return "testRole success";
    }

    @ResponseBody
    @RequestMapping(value = "/testPerms", method = RequestMethod.GET)
    public String testPerms() {
        return "testPerms success";
    }
    //测试自定义filter
	@ResponseBody
    @RequestMapping(value = "/testRole2", method = RequestMethod.GET)
    public String testRole2() {
        return "testRole2 success";
    }

    @ResponseBody
    @RequestMapping(value = "/testPerms1", method = RequestMethod.GET)
    public String testPerms1() {
        return "testPerms1 success";
    }
}

3.完整demo下载:

点击下载

4.测试:

在这里插入图片描述
首先如果没有登入输入index.html 还是回跳转到login.html页面,因为没有登入
登入后跳转:
在这里插入图片描述
其他页面也可以自己测试!

猜你喜欢

转载自blog.csdn.net/qq_42651904/article/details/88116078