ssm整合shiro 一体项目

牧云@^-^@ 提交于 2020-01-21 01:01:38

介绍

在上上一篇文章中,我对shiro进行了初步的讲解。ssm与shiro的整合不像是springboot与springsecurity整合那样免去了很多步骤,ssm与shiro的整合与shiro非web的用法十分贴近。该文章将讲解ssm整合shiro一体项目(非前后分离)。

配置说明

在看如何配置之前,为了不显得突兀,推荐看一下我上一篇文章"ssm整合"。
在这里插入图片描述
在这里插入图片描述
红框为新添加的配置文件。
application-shiro.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        ">

<!--    将凭证匹配器注册成bean为myRealm用于ref-->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <!-- 添加算法 md5-->
        <property name="hashAlgorithmName" value="md5"></property>
        <!-- 迭代加密次数为1      -->
        <property name="hashIterations" value="1"></property>
    </bean>
<!--    将java中的Realm创建成bean为securityManager用于ref-->
    <bean id="myRealm" class="com.qiu.shirobyssm.config.MyRealm">
        <!--  这里面将注入凭证匹配器(MD5) -->
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>
    </bean>
<!--    创建安全管理对象(为整合spring所特殊提供的securitymanager)-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 注入 myRealm      -->
        <property name="realm" ref="myRealm"></property>
    </bean>
<!--    创建shiro的过滤器-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理器  -->
        <property name="securityManager" ref="securityManager"></property>
        <!-- 登录url 指定一个路径专门是登录的路径, 如果认证未通过,那么会跳到指定这个路径  -->
        <property name="loginUrl" value="/startlogin"></property>
        <!--   未授权登录     请登录访问页-->
        <property name="unauthorizedUrl" value="/unauthorized"></property>
        <!--  配置过滤链 ,url的访问模式配置      -->
        <property name="filterChainDefinitions">
            <value>
                <!--   放行登录界面路径,不需要登录             -->
                /startlogin=anon
                <!--    前往登录界面的接口放行           -->
                /toLogin=anon
                <!--   输入用户名密码的接口放行             -->
                /login=anon
                <!--   退出用户 使用logout过滤器            -->
                /logout=logout
                <!--   其他的路径想要访问接口或者页面都需要验证信息 使用authc过滤器            -->
                <!--   /**最后一个写,因为他是从上到下匹配的,就是所谓的优先级             -->
                /**=authc
            </value>
        </property>
    </bean>
</beans>

配置好application-shiro.xml之后,很明显是毫无用处的,想要让这个配置文件生效还需要在applicationContext.xml引入,然后再web.xml中配置shiro相关过滤器…等诸多操作,请保持耐心

在applicationContext.xml中引入application-shiro.xml配置信息
在这里插入图片描述
在web.xml中配置shiro过滤器

	<filter>
        <!--    shiro的集成-->
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>targetBeanName</param-name>
             <!--   该value必须要符合application-shiro.xml中过滤器的id对上-->
            <param-value>shiroFilter</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <servlet-name>springmvc</servlet-name>
    </filter-mapping>

以上配置好之后,就差自定义realm的配置了。在配置realm之前,需要从数据库中获取用户、角色、权限功能等数据,因为偷懒缘故,只粘贴表结构和mapper.xml(因为没有特殊的逻辑)

UserMapper.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" >
 <!--  用户sql-->
<mapper namespace="com.qiu.shirobyssm.mapper.UserMapper">
    <select id="selUser" resultType="com.qiu.shirobyssm.pojo.User">
        select userid,username,password,solt from user where username=#{username}
    </select>
</mapper>

RoleMapper.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" >
 <!--  角色sql-->
<mapper namespace="com.qiu.shirobyssm.mapper.RoleMapper">
    <select id="selRoleByUser" resultType="com.qiu.shirobyssm.pojo.Role">
        select
            r.roleid as roleid,r.rolename as rolename
            from role as r
            left join user_role as ur on ur.roleid=r.roleid
            where ur.userid=#{userid}
    </select>
</mapper>

PerMapper

<?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" >
 <!--  权限功能sql-->
<mapper namespace="com.qiu.shirobyssm.mapper.PerMapper">
    <select id="selPerByRole" resultType="com.qiu.shirobyssm.pojo.Permission">
        SELECT
            p.perid as perid,
            p.percode as percode
            FROM permission as p
            LEFT join role_permission as rp
            on p.perid=rp.perid
            where rp.roleid=#{roleid}
    </select>
</mapper>

应该有人发现,我没有使用parameterType来指定参数类型,因为我用了另一种更灵活的方式去指定参数类型了。看下图例子,该图为PerMapper接口。
在这里插入图片描述

表结构

user表结构
在这里插入图片描述
user_role表结构
在这里插入图片描述
role表结构
在这里插入图片描述
permission表结构
在这里插入图片描述
role_permission表结构
在这里插入图片描述

表数据

user表数据
密码自己用shiro自带的md5加密工具类生成一个。
在这里插入图片描述
role表数据
在这里插入图片描述
user_role表数据
在这里插入图片描述
permission表数据
在这里插入图片描述
role_permission表数据

在这里插入图片描述

自定义Realm

myRealm.java
都是很基本的代码,注释就不写太多了

package com.qiu.shirobyssm.config;

import com.qiu.shirobyssm.pojo.Permission;
import com.qiu.shirobyssm.pojo.Role;
import com.qiu.shirobyssm.pojo.User;
import com.qiu.shirobyssm.service.PerService;
import com.qiu.shirobyssm.service.RoleService;
import com.qiu.shirobyssm.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Author VULCAN
 * @create 2020/1/19 17:10
 */
//MyRealm在配置文件中已经注册成bean了,所以可以在它的类下使用@Autowired
public class MyRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;
    @Autowired
    PerService perService;
    @Override
    public String getName(){
        return this.getClass().getSimpleName();
    }
    //角色权限添加
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<Role> roles = roleService.selRoleByUser(user.getUserid());
        Collection<String> roleNames=new ArrayList<String>();
        Collection<String> perCodes=new ArrayList<String>();
        if(roles!=null && roles.size()>0){
            for (Role role:roles){
                String rolename = role.getRolename();
                int roleid = role.getRoleid();
                roleNames.add(rolename);
                //获得所有权限功能
                List<Permission> permissions = perService.selPerByRole(roleid);
                if(permissions!=null && permissions.size()>0){
                    for (Permission permission:permissions){
                        String percode = permission.getPercode();
                        perCodes.add(percode);
                    }
                }
            }
            //增加角色
            info.addRoles(roleNames);
            //增加权限功能
            info.addStringPermissions(perCodes);
        }
        return info;
    }
    //信息验证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken info) throws AuthenticationException {
        User users = userService.selUser(info.getPrincipal().toString());
        if(users!=null){
            String password = users.getPassword();
            String username = users.getUsername();
            String solt = users.getSolt();
            ByteSource soltToByte=ByteSource.Util.bytes(solt);
            //如果与前台输入的接口不匹配,则密码错误
            SimpleAuthenticationInfo logininfo=new SimpleAuthenticationInfo(users,password,soltToByte,this.getName());
            return logininfo;
        }else{
            //返回空就表示用户名不存在
            return null;
        }

    }
}

Controller层接口配置

登录页面接口

//登录页,没有得到授权的页面都会跳到这个页面
@RequestMapping("startlogin")
    public String runStartlogin(Model model){
        model.addAttribute("login","请登录");
        return "index";
    }

内容页面接口

//内容页,不过因为配置了过滤器,只有登录成功后才能访问
    @RequestMapping("toContent")
    public String toContent(){
        return "content";
    }

登录接口

//登录接口,用户名密码的处理在这个接口中
   @RequestMapping("login")
    public String login(String username , String password ,boolean rememberme, HttpSession httpSession){
        //不需要绑定线程
        //获得主体对象
        Subject subject = SecurityUtils.getSubject();
        //得到token信息
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //记住我功能
        token.setRememberMe(rememberme);
        //开始登录,进入myrealm中,如果返回为null则代表账户不存在,会抛出异常。匹配不上,会抛出异常
        try {
            subject.login(token);
            User userinfo = (User)subject.getPrincipal();
            httpSession.setAttribute("userinfo",userinfo);
           //登录正确跳转到toContent的路径映射
            return "redirect:toContent";
        } catch (AuthenticationException e) { //CredentialsException密码与账户不匹配   //AccountException账户错误(不存在)
            System.out.println("用户名或密码有错误");
            httpSession.setAttribute("error","登录错误");
            //登录错误跳转到startlogin的路径映射
            return "redirect:startlogin";
        }
    }

web前端页面

index.jsp
我将他作为首页、登录界面

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h2>Hello World!你好iam login</h2>
${login}
<form action="${pageContext.request.contextPath}/login" method="post">
    <input name="username" type="text" placeholder="请输入用户名">
    <input name="password" type="password" placeholder="请输入密码">
<%--    登录错误后会返回error的session--%>
    ${error}
    <input type="submit" value="登录">
    <h5>是否需要记住<input type="checkbox" name="rememberme"></h5>
</form>
</body>
</html>

content.jsp
内容页,但是只有登录后才可以访问

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%--shiro标签库--%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h2>我是内容</h2>
<%--获得session中的名字 可以直接${session名}--%>
${sessionScope.userinfo.username}
<%--只有user:sel该权限功能的用户能看见被包裹的标签--%>
<shiro:hasPermission name="user:sel">
    <a>用户查询</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:add">
    <a>用户添加</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:up">
    <a>用户修改</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:del">
    <a>用户删除</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:export">
    <a>导出用户</a>
</shiro:hasPermission>
</body>
</html>

以上全部配置完毕,来查看结果
登录界面
在这里插入图片描述
错误的输入用户名与密码
在这里插入图片描述
正确的输入用户名与密码
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!