zoukankan      html  css  js  c++  java
  • 6、SSM整合Shiro

    准备

    数据库准备

    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

    SSM整合博客:https://www.coydone.com/?p=125

    【SSM整合】博客园:https://www.cnblogs.com/coydone/p/13742678.html

    使用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

    2、创建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;
        }
    }
    

    修改配置

    4、在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>
    
    coydone的博客
  • 相关阅读:
    各种排序
    最大子数组的和与积
    字符串距离
    二叉树的基本操作
    C++11创建线程的几种方式
    二分查找
    汉诺塔问题
    读写锁实现
    全排列
    数字转汉字
  • 原文地址:https://www.cnblogs.com/coydone/p/13779977.html
Copyright © 2011-2022 走看看