侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

SSM整合Shiro

coydone
2022-03-29 / 0 评论 / 0 点赞 / 389 阅读 / 24,284 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

源码:ssm_shiro.zip

准备

数据库准备

Permission:权限表。

Role:角色表。

Role_permission:权限和角色的关系表。

User:用户表。

User_role:用户和角色和关系表。

create database ssm_shiro;
user ssm_shiro;
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
  `perid` INT(11) NOT NULL AUTO_INCREMENT,
  `pername` VARCHAR(255) DEFAULT NULL,
  `percode` VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (`perid`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `permission` VALUES ('1', '用户查询', 'user:query');
INSERT INTO `permission` VALUES ('2', '用户添加', 'user:add');
INSERT INTO `permission` VALUES ('3', '用户修改', 'user:update');
INSERT INTO `permission` VALUES ('4', '用户删除', 'user:delete');
INSERT INTO `permission` VALUES ('5', '导出用户', 'user:export');

DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `roleid` INT(11) NOT NULL AUTO_INCREMENT,
  `rolename` VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (`roleid`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `role` VALUES ('1', '超级管理员');
INSERT INTO `role` VALUES ('2', 'CEO');
INSERT INTO `role` VALUES ('3', '保安');

DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
  `perid` INT(255) DEFAULT NULL,
  `roleid` INT(11) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `role_permission` VALUES ('1', '1');
INSERT INTO `role_permission` VALUES ('2', '1');
INSERT INTO `role_permission` VALUES ('3', '1');
INSERT INTO `role_permission` VALUES ('4', '1');
INSERT INTO `role_permission` VALUES ('1', '2');
INSERT INTO `role_permission` VALUES ('2', '2');
INSERT INTO `role_permission` VALUES ('3', '2');
INSERT INTO `role_permission` VALUES ('1', '3');
INSERT INTO `role_permission` VALUES ('5', '3');

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `userid` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(255) DEFAULT NULL,
  `userpwd` VARCHAR(255) DEFAULT NULL,
  `sex` VARCHAR(255) DEFAULT NULL,
  `address` VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (`userid`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES ('1', 'zhangsan', '639ffb0cbcca39d4fff8348844b1974e', '男', '武汉');
INSERT INTO `user` VALUES ('2', 'lisi', '0d303fa8e2e2ca98555f23a731a58dd9', '女', '北京');
INSERT INTO `user` VALUES ('3', 'wangwu', '473c41db9af5cc0d90e7adfd2b6d9180', '女', '成都');

DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `userid` INT(11) DEFAULT NULL,
  `roleid` INT(11) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user_role` VALUES ('1', '1');
INSERT INTO `user_role` VALUES ('2', '2');
INSERT INTO `user_role` VALUES ('3', '3');

数据结构

张三:user:query、user:add、user:update、user:delete。

李四:user:query 、user:add、user:update。

王五:user:query、user:export。

密码说明:使用登录名和地址作为盐、散列2次。

搭建SSM环境

略,可以参考gitee的SSM整合:https://gitee.com/coydone/ssm_crud/tree/master。

使用MBG自动生成mapper代码。

整合Shiro

pom文件导入shiro依赖

<!-- shiro -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

编写数据库实体

使用MBG工具自动生成,略。可以在实体上实现序列化接口。

public class User implements Serializable {}

编写mapper

mapper层接口和mapper.xml文件由MBG工具自动生成,略。

修改mapper层、添加MBG没有提供的方法。

  • PermissionMapper
List<Permission> queryPermissionsByUserId(Integer userid);
<!-- 根据用户ID查询用户拥有的权限 -->
<select id="queryPermissionsByUserId"  resultMap="BaseResultMap">
    select distinct t1.* from permission t1 inner join role_permission t2 inner join user_role t3
    on(t1.perid=t2.perid and t2.roleid=t3.roleid)
    where t3.userid=#{userid}
</select>
  • RoleMapper
List<Role> queryRolesByUserId(Integer userid);
<!-- 根据用户ID查询用户拥有的角色 -->
<select id="queryRolesByUserId"  resultMap="BaseResultMap">
    select t1.* from role t1 inner join user_role t2 on(t1.roleid=t2.roleid)
    where t2.userid=#{userid}
</select>
  • UserMapper
User queryUserByUserName(String username);
<!-- 根据用户名查询用户 -->
<select id="queryUserByUserName" resultMap="BaseResultMap">
    select * from user where username=#{username}
</select>

编写service层

  • PermissionService
public interface PermissionService {

   /**
    * 根据用户ID查询用户拥有的权限
    * @param userid
    * @return
    */
   List<String> queryPermissionsByUserId(Integer userid);
}

package com.coydone.service.impl;
@Service
public class PermissionServiceImpl implements PermissionService {

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public List<String> queryPermissionsByUserId(Integer userid) {

        List<Permission> permissionList=permissionMapper.queryPermissionsByUserId(userid);
        List<String> permissions=new ArrayList<>();

        for (Permission permission : permissionList) {
            permissions.add(permission.getPercode());
        }
        return permissions;
    }
}
  • RoleService
public interface RoleService {

	/**
	 * 根据用户ID查询用户拥有的角色
	 * @param userid
	 * @return
	 */
	List<String> queryRolesByUserId(Integer userid);
}

@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
    public List<String> queryRolesByUserId(Integer userid) {
        List<Role> roleList=roleMapper.queryRolesByUserId(userid);
        List<String> roles=new ArrayList<String>();
        for (Role role : roleList) {
            roles.add(role.getRolename());
        }
        return roles;
    }

}
  • UserService
public interface UserService {
    /**
	 * 根据用户名查询用户对象
	 * @param username
	 * @return
	 */
    User queryUserByUserName(String username);
}

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public User queryUserByUserName(String username) {
        User user=userMapper.queryUserByUserName(username);
        return user;
    }
}

我们需要将用户的信息、角色、权限存储到session中,于是我们定义一个ActiveUser封装我们需要的这些信息。

package com.coydone.utils;
import com.coydone.entity.User;
import java.util.List;
public class ActiveUser {
   private User user;
   private List<String> roles;
   private List<String> permissions;
   //省略getter()、setter()、有参、无参构造
}

编写Controller

@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("loadAllUser")
    public String loadAllUser() {
        return "list";
    }
}

@Controller
@RequestMapping("login")
public class LoginController {
    /**
	 * 跳转到登陆页面
	 */
    @RequestMapping("toLogin")
    public String toLogin() {
        return "login";
    }
    /**
	 * 完成登陆的方法
	 */
    @RequestMapping("login")
    public String login(String username, String password, HttpSession session) {
        // 1,得到主体
        Subject subject = SecurityUtils.getSubject();
        // 2,封装用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            ActiveUser activerUser = (ActiveUser) subject.getPrincipal();
            session.setAttribute("user", activerUser.getUser());
            return "redirect:/user/loadAllUser";
        } catch (AuthenticationException e) {
            System.out.println("用户名或密码不正确");
        }	
        return "redirect:index.jsp";
    }
}

自定义Realm

创建UserRealm

package com.coydone.realm;

import com.coydone.entity.User;
import com.coydone.service.PermissionService;
import com.coydone.service.RoleService;
import com.coydone.service.UserService;
import com.coydone.utils.ActiveUser;
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.Arrays;
import java.util.List;
public class UserRealm extends AuthorizingRealm {
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permssionService;
    /**
     * 完成认证的方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = token.getPrincipal().toString();
        Object credentials = token.getCredentials();// 用户登陆时传过来的
        System.out.println(Arrays.toString((char[]) credentials));
        // 根据用户名查询用户是否存在
        User user = this.userService.queryUserByUserName(username);
        // 返回null说明用户不存在
        if (null != user) {
            // 根据用户名去查询用户拥有哪些角色
            List<String> roles = roleService.queryRolesByUserId(user.getUserid());
            // 根据用户名查询用户拥有哪些权限
            List<String> permissions = this.permssionService.queryPermissionsByUserId(user.getUserid());
            ActiveUser activeUser = new ActiveUser(user, roles, permissions);
            /**
             * 参数1 用户身份 参数2 用户在数据库里面存放的密码 参数3 当前类名
             */
            // SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(activeUser,
            // user.getPassword(), this.getName());
            /**
             * 参数1:传到doGetAuthorizationInfo里面getPrimaryPrincipal()的对象或者subject.getPrincipal()
             * 参数2:hashedCredentials 加密之后的密码 参数3:credentialsSalt 盐
             */
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername()+user.getAddress());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activeUser, user.getUserpwd(), credentialsSalt,
                    this.getName());

            return info;
        }
        return null;
    }
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 根据用户名去查询用户拥有哪些角色
        List<String> roles = activeUser.getRoles();
        if (null != roles && roles.size() > 0) {
            // 添加角色
            info.addRoles(roles);
        }
        // 根据用户名查询用户拥有哪些权限
        List<String> permissions = activeUser.getPermissions();
        // 添加权限
        if (null != permissions && permissions.size() > 0) {
            // 添加角色
            info.addStringPermissions(permissions);
        }
        return info;
    }
}

修改配置

在Spring的配置文件中配置Shiro。

<!-- ============== 配置shiro 开始=============  -->
<!-- 声明凭证匹配器 -->
<bean id="credentialsMatcher"
      class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    <!-- 注入加密方式 -->
    <property name="hashAlgorithmName" value="md5"></property>
    <!-- 注入散列次数 -->
    <property name="hashIterations" value="2"></property>
</bean>

<!-- 声明userRealm -->
<bean id="userRealm" class="com.coydone.realm.UserRealm">
    <!-- 注入凭证匹配器 -->
    <property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>

<!-- 声明安全管理器 -->
<bean id="securityManager"
      class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <!-- 注入realm -->
    <property name="realm" ref="userRealm"></property>
</bean>

<!-- 配置shrio的过滤器链 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 注入安全管理器 -->
    <property name="securityManager" ref="securityManager"></property>
    <!-- 注入如果没认证  跳转的页面 -->
    <property name="loginUrl" value="/index.jsp"></property>
    <!-- 未授权的跳转页 -->
    <property name="unauthorizedUrl" value="login/toUnauthorized"></property>

    <property name="filterChainDefinitions">
        <value>
            <!-- 放行系统首页 -->
            /index.jsp*=anon
            <!-- 放行跳转到登陆页面的地  -->
            /login/toLogin*=anon
            <!-- 放行登陆的方法 -->
            /login/login*=anon
            <!-- 其它的页面都要认证 -->
            /**=authc
        </value>
    </property>
</bean>
<!-- ============== 配置shiro 结束=============  -->

修改web.xml。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- 配置shiro的代理过滤器 开始 -->
    <filter>
        <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>
            <!-- 这里的shrioFilter必须和spring配置shiro里面的  过滤器ID一致 -->
            <param-name>targetBeanName</param-name>
            <param-value>shiroFilter</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <servlet-name>dispatcherServlet</servlet-name>
    </filter-mapping>
    <!-- 配置shiro的代理过滤器 结束 -->

    <!-- 配置编码过滤器开始 -->
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 注入属性 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <!-- <url-pattern>/*</url-pattern> -->
        <servlet-name>dispatcherServlet</servlet-name>
    </filter-mapping>
    <!-- 配置编码过滤器结束 -->

    <!--配置全局参数-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!--监听全局配置参数-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--配置springmvc的核心拦截器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

编写页面

  • index.jsp
<body>
<jsp:forward page="login/toLogin"></jsp:forward>
</body>
  • login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1 align="center">用户登陆</h1>
        <hr> 
        <form action="${pageContext.request.contextPath}/login/login" method="post">
            <table align="center" width="50%" border="1" cellpadding="2" cellspacing="5">
                <tr>
                    <td align="right">用户名:</td>
                    <td>
                        <input type="text" name="username">
                    </td>
                </tr>
                <tr>
                    <td align="right">密码:</td>
                    <td>
                        <input type="password" name="password">
                    </td>
                </tr>
                <tr>
                    <td colspan="2" align="center">
                        <input type="submit" value="登陆">
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>
  • list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <shiro:hasPermission name="user:query">
            <h2>
                <a href="">查询用户</a>
            </h2>
        </shiro:hasPermission>
        <shiro:hasPermission name="user:add">
            <h2>
                <a href="">添加用户</a>
            </h2>
        </shiro:hasPermission>
        <shiro:hasPermission name="user:update">
            <h2>
                <a href="">修改用户</a>
            </h2>
        </shiro:hasPermission>
        <shiro:hasPermission name="user:delete">
            <h2>
                <a href="">删除用户</a>
            </h2>
        </shiro:hasPermission>
        <shiro:hasPermission name="user:export">
            <h2>
                <a href="">导出用户</a>
            </h2>
        </shiro:hasPermission>
    </body>
</html>

实现记住我功能

1、在登陆页面添加记住我的复选框

<tr>
    <td colspan="2">
        <input type="checkbox" name="rememberMe" value="1" > 记住我
    </td>
</tr>

2、修改LoginController

3、修改Spring中对Shiro的配置。

包括配置cookie、配置rememberMe、并注入到安全管理器中,然后修改需要认证的页面。

<!-- ============== 配置shiro 开始=============  -->
<!-- cookie的配置 -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="rememberMe"></constructor-arg>
    <!-- 只有http请求时才能使用cookie -->
    <property name="httpOnly" value="true"></property>
    <!-- 设置cookie的存活时间   7天  单位为秒 -->
    <property name="maxAge" value="604800"></property>
</bean>
<!-- 声明记住我的管理对象 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
    <property name="cookie" ref="rememberMeCookie"></property>
</bean>

<!-- 声明凭证匹配器 -->
<bean id="credentialsMatcher"
      class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    <!-- 注入加密方式 -->
    <property name="hashAlgorithmName" value="md5"></property>
    <!-- 注入散列次数 -->
    <property name="hashIterations" value="2"></property>
</bean>

<!-- 声明userRealm -->
<bean id="userRealm" class="com.coydone.realm.UserRealm">
    <!-- 注入凭证匹配器 -->
    <property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>

<!-- 声明安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <!-- 注入realm -->
    <property name="realm" ref="userRealm"></property>
    <!-- 注入rememberMeManager -->
    <property name="rememberMeManager" ref="rememberMeManager"></property>
</bean>

<!-- 配置shrio的过滤器链 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 注入安全管理器 -->
    <property name="securityManager" ref="securityManager"></property>
    <!-- 注入如果没认证  跳转的页面 -->
    <property name="loginUrl" value="/index.jsp"></property>
    <!-- 未授权的跳转页 -->
    <property name="unauthorizedUrl" value="login/toUnauthorized"></property>

    <property name="filterChainDefinitions">
        <value>
            <!-- 放行系统首页 -->
            /index.jsp*=anon
            <!-- 放行跳转到登陆页面的地  -->
            /login/toLogin*=anon
            <!-- 放行登陆的方法 -->
            /login/login*=anon
            <!-- 其它的页面都要认证 -->
            /**=user
            /*=authc
            /*/*=authc
        </value>
    </property>
</bean>
<!-- ============== 配置shiro 结束=============  -->

4、在shiro里面使用的类实现序列化接口,包括User、Permission、Role、ActiveUser。

public class Permission implements Serializable {}
public class Role implements Serializable {}
public class User implements Serializable{}
public class ActiveUser implements Serializable {}

5、解决session无法获取的问题

此时shiro官方提供的rememberMe方法无法满足我们的业务需求,我们需要重写它提供的方法。

  • 创建RememberMeFilter
package com.coydone.filter;

import com.coydone.utils.ActiveUser;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class RememberMeFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue)
        throws Exception {
        Subject subject=getSubject(request, response);
        Session session=subject.getSession();
        //记住我的功能isAuthenticated肯定为false 而isRemembered肯定为true
        if(!subject.isAuthenticated()&&subject.isRemembered()&&session.getAttribute("user")==null) {
            //说明是记住我的功能
            ActiveUser activeUser=(ActiveUser) subject.getPrincipal();
            if(null!=activeUser) {
                session.setAttribute("user", activeUser.getUser());
            }
        }
        return true;
    }
}
  • 在Spring的配置文件中注入我们自定义的RememberMeFilter。
<!-- 声明自定义RememberMeFilter -->
<bean id="RememberMeFilter" class="com.coydone.filter.RememberMeFilter"></bean>

<!-- 配置shrio的过滤器链 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 注入自定义过滤器 -->
    <property name="filters">
        <map>
            <entry key="rememberMe" value-ref="RememberMeFilter"></entry>
        </map>
    </property>
</bean>
<property name="filterChainDefinitions">
    <value>
        <!-- 其它的页面都要认证 -->
        /**=rememberMe,user
        /*=authc
        /*/*=authc
    </value>
</property>

6、测试

在list.jsp中添加${user.username},登录选择记住我,关闭浏览器,直接访问list页面,发现会显示用户名。

前后端分离配置

1、修改控制器中改为向页面输出json。

@RestController
@RequestMapping("user")
public class UserController {
    @RequestMapping("query")
    @RequiresPermissions("user:query")
    public Map<String,Object> query(){
        Map<String,Object> map=new HashMap<>();
        map.put("msg", "query");
        return map;
    }
}

2、创建GlobalExceptionHanderAdvise全局异常监控。

//全局的异常监控
//@ControllerAdvice  这个注解是监视Controller里面是否有异常发生,如果发生就跳转页面
@RestControllerAdvice 
public class GlobalExceptionHanderAdvise {
    //未授权
    @ExceptionHandler(value= {UnauthorizedException.class})
    public Object unauthorized() {
        Map<String,Object> map=new HashMap<>();
        map.put("code", -1);
        map.put("msg", "未授权,请联系管理员");
        return map;
    }
}

3、修改springmvc.xml开启Shiro注解。

<!-- 扫描异常监视器 -->
<context:component-scan base-package="com.coydone.exception"></context:component-scan>
<!-- 启动Shrio的注解 -->
<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>

4、解决未登陆不使用重定向使用JSON的问题。

创建ShiroLoginFilter

public class ShiroLoginFilter  extends FormAuthenticationFilter {
    /**
     * 在访问controller前判断是否登录,返回json,不进行重定向。
     * @param request
     * @param response
     * @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        //if (isAjax(request)) {
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            Map<String,Object> resultData = new HashMap<>();
            resultData.put("code", -1);
            resultData.put("msg", "登录认证失效,请重新登录!");          httpServletResponse.getWriter().write(JSONObject.toJSON(resultData).toString());
    /*  } else {
            // saveRequestAndRedirectToLogin(request, response);
             //非ajax请求重定向为登录页面
            httpServletResponse.sendRedirect("/login");
        }*/
        return false;
    }
    private boolean isAjax(ServletRequest request) {
        String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
        if ("XMLHttpRequest".equalsIgnoreCase(header)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
}

5、修改Spring中对Shiro的配置【覆盖authc的过滤器】

<property name="filters">
    <map>
        <entry key="authc">
            <bean class="com.coydone.filter.ShiroLoginFilter"></bean>
        </entry>
    </map>
</property>
<property name="filterChainDefinitions">
    <value>
        <!-- /** = authc 所有url都必须认证通过才可以访问 -->
        /index.jsp*=anon
        /login/toLogin*=anon
        /login/login*=anon
        <!-- 如果用户访问user/logout就使用Shiro注销session -->
        /login/logout = logout
        <!-- /** = anon所有url都不可以匿名访问 -->
        <!-- /** = authc -->
        <!-- /*/* = authc -->
        <!-- /** = authc所有url都不可以匿名访问 必须放到最后面 -->
        /** = authc
    </value>
</property>
0

评论区