SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

一套系统,除了个人网站,一般都要有多种角色,每种角色必须严格控制它的权限。

Shiro是一种轻量级的安全框架,主要是做登录验证,权限检查,相对 Spring Security 是要简单很多,源码也很清晰。

本文通过实战做一个介绍。

一、准备

1.pom.xml

本文采用 SpringBoot2.0.5 + MyBatis + MyBatis Plus

下面是 Shiro 的依赖

  1. <!--Shiro-->
  2. <dependency>
  3.   <groupId>org.apache.shiro</groupId>
  4.   <artifactId>shiro-spring</artifactId>
  5.   <version>1.4.0</version>
  6. </dependency>

 

其他依赖就不贴,如果缺少,可以在下面评论取索取,或者在 Maven 上搜

 

2.数据库

5张表

① user 表

  1. CREATE TABLE `sens_user` (
  2.   `user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  3.   `login_enable` varchar(255) DEFAULT NULL,
  4.   `login_error` int(11) DEFAULT NULL,
  5.   `login_last` datetime DEFAULT NULL,
  6.   `user_avatar` varchar(255) DEFAULT NULL,
  7.   `user_desc` varchar(255) DEFAULT NULL,
  8.   `user_display_name` varchar(255) DEFAULT NULL,
  9.   `user_email` varchar(255) DEFAULT NULL,
  10.   `user_name` varchar(255) DEFAULT NULL,
  11.   `user_pass` varchar(255) DEFAULT NULL,
  12.   `user_site` varchar(255) DEFAULT NULL,
  13.   `status` int(1) DEFAULT NULL,
  14.   `create_time` datetime DEFAULT NULL,
  15.   PRIMARY KEY (`user_id`)
  16. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

 

②  role 表

  1. CREATE TABLE `sens_rbac_role` (
  2.   `id` int(11) NOT NULL,
  3.   `role` varchar(255) DEFAULT NULL,
  4.   `description` varchar(255) DEFAULT NULL
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

 

③ permission 表

  1. CREATE TABLE `sens_rbac_permission` (
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,
  3.   `namevarchar(255) DEFAULT NULL,
  4.   `permission` varchar(255) DEFAULT NULL,
  5.   PRIMARY KEY (`id`)
  6. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

 

④ user_role_ref 表

  1. CREATE TABLE `sens_rbac_user_role_ref` (
  2.   `user_id` int(20) DEFAULT NULL,
  3.   `role_id` int(11) DEFAULT NULL
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

 

⑤ role_permission_ref 表

  1. CREATE TABLE `sens_rbac_role_permission_ref` (
  2.   `role_id` int(11) DEFAULT NULL,
  3.   `permission_id` int(11) DEFAULT NULL
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

 

 

备注:

本来还有一张菜单表,不属于本文的范畴,就不介绍了。

跟权限有关的,表名加前缀 rbac_,项目名叫 sens,表名加前缀 sens_

 

二、基础代码(Model,Dao和Service层)

1.Model 实体

User.java

  1. package com.liuyanzhao.sens.entity;
  2. import com.baomidou.mybatisplus.annotations.TableId;
  3. import com.baomidou.mybatisplus.annotations.TableName;
  4. import com.baomidou.mybatisplus.enums.IdType;
  5. import com.fasterxml.jackson.annotation.JsonIgnore;
  6. import lombok.Data;
  7. import javax.validation.constraints.Email;
  8. import javax.validation.constraints.NotBlank;
  9. import java.io.Serializable;
  10. import java.util.Date;
  11. /**
  12.  * <pre>
  13.  *     博主信息
  14.  * </pre>
  15.  *
  16.  * @author : saysky
  17.  * @date : 2017/11/14
  18.  */
  19. @Data
  20. @TableName("sens_user")
  21. public class User implements Serializable {
  22.     private static final long serialVersionUID = -5144055068797033748L;
  23.     /**
  24.      * 编号
  25.      */
  26.     @TableId(type = IdType.AUTO)
  27.     private Long userId;
  28.     /**
  29.      * 用户名
  30.      */
  31.     @NotBlank(message = "用户名不能为空")
  32. //    @JsonIgnore
  33.     private String userName;
  34.     /**
  35.      * 显示名称
  36.      */
  37.     private String userDisplayName;
  38.     /**
  39.      * 密码
  40.      */
  41. //    @JsonIgnore
  42.     private String userPass;
  43.     /**
  44.      * 邮箱
  45.      */
  46.     @Email(message = "邮箱格式不正确")
  47.     private String userEmail;
  48.     /**
  49.      * 头像
  50.      */
  51.     private String userAvatar;
  52.     /**
  53.      * 说明
  54.      */
  55.     private String userDesc;
  56.     /**
  57.      * 个人主页
  58.      */
  59.     private String userSite;
  60.     /**
  61.      * 是否禁用登录
  62.      */
  63. //    @JsonIgnore
  64.     private String loginEnable = "true";
  65.     /**
  66.      * 最后一次登录时间
  67.      */
  68. //    @JsonIgnore
  69.     private Date loginLast;
  70.     /**
  71.      * 登录错误次数记录
  72.      */
  73. //    @JsonIgnore
  74.     private Integer loginError = 0;
  75.     /**
  76.      * 0 正常
  77.      * 1 禁用
  78.      * 2 已删除
  79.      */
  80.     private Integer status = 0;
  81.     /**
  82.      * 注册时间
  83.      */
  84.     private Date createTime;
  85. }

 

Role.java

  1. package com.liuyanzhao.sens.entity;
  2. import com.baomidou.mybatisplus.annotations.TableField;
  3. import com.baomidou.mybatisplus.annotations.TableName;
  4. import lombok.Data;
  5. import java.io.Serializable;
  6. /**
  7.  * @author liuyanzhao
  8.  */
  9. @Data
  10. @TableName("sens_rbac_role")
  11. public class Role implements Serializable  {
  12.     private static final long serialVersionUID = 2233979806802117985L;
  13.     /**
  14.      * ID
  15.      */
  16.     private Integer id;
  17.     /**
  18.      * 角色名称:admin,author,subscriber
  19.      */
  20.     private String role;
  21.     /**
  22.      * 描述:管理员,作者,订阅者
  23.      */
  24.     private String description;
  25.     /**
  26.      * 该角色对应的用户数量,非数据库字段
  27.      */
  28.     @TableField(exist = false)
  29.     private Integer count;
  30. }

 

Permisison.java

  1. package com.liuyanzhao.sens.entity;
  2. import com.baomidou.mybatisplus.annotations.TableName;
  3. import lombok.Data;
  4. import java.io.Serializable;
  5. /**
  6.  * @author liuyanzhao
  7.  */
  8. @Data
  9. @TableName("sens_rbac_permission")
  10. public class Permission implements Serializable  {
  11.     private static final long serialVersionUID = 2233979806802117985L;
  12.     /**
  13.      * ID
  14.      */
  15.     private Integer id;
  16.     /**
  17.      * 权限名称
  18.      */
  19.     private String name;
  20.     /**
  21.      * 权限:user:list,user:add等
  22.      */
  23.     private String permission;
  24. }

 

UserRoleRef.java

  1. package com.liuyanzhao.sens.entity;
  2. import com.baomidou.mybatisplus.annotations.TableName;
  3. import lombok.Data;
  4. import java.io.Serializable;
  5. @Data
  6. @TableName("sens_rbac_user_role_ref")
  7. public class UserRoleRef implements Serializable {
  8.     private static final long serialVersionUID = -1528306395712515362L;
  9.     /**
  10.      * 用户Id
  11.      */
  12.     private Long userId;
  13.     /**
  14.      * 角色Id
  15.      */
  16.     private Integer roleId;
  17. }

 

RolePermission.java

  1. package com.liuyanzhao.sens.entity;
  2. import com.baomidou.mybatisplus.annotations.TableName;
  3. import lombok.Data;
  4. import java.io.Serializable;
  5. @Data
  6. @TableName("sens_rbac_role_permission_ref")
  7. public class RolePermissionRef implements Serializable {
  8.     private static final long serialVersionUID = -4015823675140925791L;
  9.     /**
  10.      * 角色Id
  11.      */
  12.     private Integer roleId;
  13.     /**
  14.      * 权限Id
  15.      */
  16.     private Integer permissionId;
  17. }

 

2.Mapper类

UserMapper.java

  1. package com.liuyanzhao.sens.mapper;
  2. import com.baomidou.mybatisplus.mapper.BaseMapper;
  3. import com.baomidou.mybatisplus.plugins.pagination.Pagination;
  4. import com.liuyanzhao.sens.entity.User;
  5. import org.apache.ibatis.annotations.Mapper;
  6. import org.apache.ibatis.annotations.Param;
  7. import java.util.List;
  8. /**
  9.  * @author liuyanzhao
  10.  */
  11. @Mapper
  12. public interface UserMapper extends BaseMapper<User> {
  13.     /**
  14.      * 查询所有
  15.      *
  16.      * @return 用户列表
  17.      */
  18.     List<User> findAll(Pagination page);
  19.     /**
  20.      * 根据角色Id获得用户
  21.      *
  22.      * @param roleId 角色Id
  23.      * @param pagination 分页信息
  24.      * @return 用户列表
  25.      */
  26.     List<User> findByRoleId(@Param("roleId") Integer roleId, Pagination pagination);
  27.     /**
  28.      * 根据用户名获得用户
  29.      *
  30.      * @param userName 用户名
  31.      * @return 用户
  32.      */
  33.     User findByUserName(String userName);
  34.     /**
  35.      * 根据用户邮箱获得用户
  36.      *
  37.      * @param userEmail 邮箱
  38.      * @return 用户
  39.      */
  40.     User findByUserEmail(String userEmail);
  41.     /**
  42.      * 根据用户Id获得用户
  43.      * @param userId 用户Id
  44.      * @return 用户
  45.      */
  46.     User findByUserId(Long userId);
  47. }

 

RoleMapper.java

  1. package com.liuyanzhao.sens.mapper;
  2. import com.baomidou.mybatisplus.mapper.BaseMapper;
  3. import com.liuyanzhao.sens.entity.Role;
  4. import org.apache.ibatis.annotations.Mapper;
  5. import java.util.List;
  6. /**
  7.  * @author liuyanzhao
  8.  */
  9. @Mapper
  10. public interface RoleMapper extends BaseMapper<Role> {
  11.     /**
  12.      * 根据用户Id获得角色列表
  13.      *
  14.      * @param userId 用户Id
  15.      * @return 角色列表
  16.      */
  17.     List<Role> findByUserId(Long userId);
  18.     /**
  19.      * 根据名称获得角色
  20.      *
  21.      * @param roleName 角色名
  22.      * @return 角色
  23.      */
  24.     Role findByRoleName(String roleName);
  25.     /**
  26.      * 获得角色列表
  27.      *
  28.      * @return 角色列表
  29.      */
  30.     List<Role> findAll();
  31.     /**
  32.      * 删除用户和角色管理
  33.      *
  34.      * @param userId 用户ID
  35.      * @return 影响行数
  36.      */
  37.     Integer deleteByUserId(Long userId);
  38.     /**
  39.      * 统计某个角色的用户数
  40.      *
  41.      * @param roleId 角色Id
  42.      * @return 用户数
  43.      */
  44.     Integer countUserByRoleId(Integer roleId);
  45. }

 

PermissionMapper.java

  1. package com.liuyanzhao.sens.mapper;
  2. import com.baomidou.mybatisplus.mapper.BaseMapper;
  3. import com.liuyanzhao.sens.entity.Permission;
  4. import org.apache.ibatis.annotations.Mapper;
  5. import java.util.List;
  6. /**
  7.  * @author liuyanzhao
  8.  */
  9. @Mapper
  10. public interface PermissionMapper extends BaseMapper<Permission> {
  11.     /**
  12.      * 根据角色Id获得权限列表
  13.      *
  14.      * @param roleId 角色Id
  15.      * @return 权限列表
  16.      */
  17.     List<Permission> findByRoleId(Integer roleId);
  18.     /**
  19.      * 获得权限列表
  20.      *
  21.      * @return 权限列表
  22.      */
  23.     List<Permission> findAll();
  24. }

 

备注:

关于UserRoleRefMapper.java 和 RolePermissionRefMapper.java 本文没有涉及到,不贴了

 

3.Mapper  xml

UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.liuyanzhao.sens.mapper.UserMapper">
  4.   <resultMap id="BaseResultMap" type="com.liuyanzhao.sens.entity.User">
  5.     <id column="user_id" jdbcType="INTEGER" property="userId"/>
  6.     <result column="user_name" jdbcType="VARCHAR" property="userName"/>
  7.     <result column="user_display_name" jdbcType="VARCHAR" property="userDisplayName"/>
  8.     <result column="user_pass" jdbcType="VARCHAR" property="userPass"/>
  9.     <result column="user_email" jdbcType="VARCHAR" property="userEmail"/>
  10.     <result column="user_avatar" jdbcType="VARCHAR" property="userAvatar"/>
  11.     <result column="user_desc" jdbcType="VARCHAR" property="userDesc"/>
  12.     <result column="user_site" jdbcType="VARCHAR" property="userSite"/>
  13.     <result column="login_enable" jdbcType="VARCHAR" property="loginEnable"/>
  14.     <result column="login_last" jdbcType="TIMESTAMP" property="loginLast"/>
  15.     <result column="login_error" jdbcType="INTEGER" property="loginError"/>
  16.     <result column="status" jdbcType="INTEGER" property="status"/>
  17.     <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
  18.   </resultMap>
  19.   <sql id="all_columns">
  20.    user_id, user_name, user_display_name, user_pass, user_email,
  21.    user_avatar, user_desc, user_site, login_enable, login_last,
  22.    login_error, status, create_time
  23.    </sql>
  24.   <sql id="normal">0</sql>
  25.   <sql id="all_columns_with_table_name">
  26.     sens_user.user_id, sens_user.user_name, sens_user.user_display_name,
  27.     sens_user.user_pass, sens_user.user_email, sens_user.user_avatar,
  28.     sens_user.user_desc, sens_user.user_site, sens_user.login_enable,
  29.     sens_user.login_last, sens_user.login_error, sens_user.status, sens_user.create_time
  30.   </sql>
  31.   <sql id="tb">`sens_user`</sql>
  32.   <sql id="all_values">
  33.         #{userId}, #{userName}, #{userDisplayName}, #{userEmail}, #{userPass},
  34.         #{userAvatar}, #{userDesc}, #{userSite}, #{loginEnable}, #{loginLast},
  35.         #{loginError}, #{status}, #{createTime}
  36.     </sql>
  37.   <select id="findAll" resultMap="BaseResultMap">
  38.     SELECT
  39.     <include refid="all_columns"/>
  40.     FROM
  41.     <include refid="tb"/>
  42.   </select>
  43.   <select id="findByRoleId" resultType="com.liuyanzhao.sens.entity.User">
  44.     SELECT
  45.     <include refid="all_columns_with_table_name"/>
  46.     FROM sens_rbac_user_role_ref,
  47.     sens_user WHERE sens_rbac_user_role_ref.role_id = #{roleId} AND
  48.     sens_rbac_user_role_ref.user_id = sens_user.user_id
  49.   </select>
  50.   <select id="findByUserName" resultType="com.liuyanzhao.sens.entity.User">
  51.     SELECT
  52.     <include refid="all_columns"/>
  53.     FROM
  54.     <include refid="tb"/>
  55.     WHERE user_name = #{value} AND status = <include refid="normal"/> LIMIT 1
  56.   </select>
  57.   <select id="findByUserEmail" resultType="com.liuyanzhao.sens.entity.User">
  58.     SELECT
  59.     <include refid="all_columns"/>
  60.     FROM
  61.     <include refid="tb"/>
  62.     WHERE user_email = #{value} AND status = <include refid="normal"/> LIMIT 1
  63.   </select>
  64.   <select id="findByUserId" resultType="com.liuyanzhao.sens.entity.User">
  65.     SELECT
  66.     <include refid="all_columns"/>
  67.     FROM
  68.     <include refid="tb"/>
  69.     WHERE user_id = #{value}
  70.   </select>
  71. </mapper>

 

RoleMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.liuyanzhao.sens.mapper.RoleMapper">
  4.   <resultMap id="BaseResultMap" type="com.liuyanzhao.sens.entity.Role">
  5.     <id column="id" jdbcType="INTEGER" property="id"/>
  6.     <result column="role" jdbcType="VARCHAR" property="role"/>
  7.     <result column="description" jdbcType="VARCHAR" property="description"/>
  8.   </resultMap>
  9.   <sql id="all_columns">
  10.     id, role, description
  11.   </sql>
  12.   <sql id="tb">`sens_rbac_role`</sql>
  13.   <sql id="all_values">
  14.         #{id}, #{role}, #{description}
  15.   </sql>
  16.   <sql id="all_values_with_table_name">
  17.     sens_rbac_role.id, sens_rbac_role.role, sens_rbac_role.description
  18.   </sql>
  19.   <select id="findByUserId" resultType="com.liuyanzhao.sens.entity.Role">
  20.     select
  21.     <include refid="all_values_with_table_name"/>
  22.     FROM<include refid="tb"/>, sens_rbac_user_role_ref
  23.     where sens_rbac_user_role_ref.user_id = #{value} AND
  24.     sens_rbac_role.id = sens_rbac_user_role_ref.role_id
  25.   </select>
  26.   <select id="findByRoleName" resultType="com.liuyanzhao.sens.entity.Role">
  27.     SELECT
  28.     <include refid="all_columns"/>
  29.     FROM
  30.     <include refid="tb"/>
  31.     WHERE role = #{value} LIMIT 1
  32.   </select>
  33.   <select id="findAll" resultType="com.liuyanzhao.sens.entity.Role">
  34.     SELECT
  35.     <include refid="all_columns"/>
  36.     FROM
  37.     <include refid="tb"/>
  38.   </select>
  39.   <delete id="deleteByUserId">
  40.     DELETE FROM sens_rbac_user_role_ref
  41.     WHERE user_id = #{value}
  42.   </delete>
  43.   <select id="countUserByRoleId" resultType="java.lang.Integer">
  44.     SELECT count(*) FROM sens_rbac_user_role_ref,sens_user
  45.      WHERE sens_rbac_user_role_ref.role_id = #{value} AND
  46.      sens_rbac_user_role_ref.user_id = sens_user.user_id
  47.   </select>
  48. </mapper>

 

PermissionMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.liuyanzhao.sens.mapper.PermissionMapper">
  4.   <resultMap id="BaseResultMap" type="com.liuyanzhao.sens.entity.Permission">
  5.     <id column="id" jdbcType="INTEGER" property="id"/>
  6.     <result column="name" jdbcType="VARCHAR" property="name"/>
  7.     <result column="permission" jdbcType="VARCHAR" property="permission"/>
  8.   </resultMap>
  9.   <sql id="all_columns">
  10.     id, `name`, permission
  11.   </sql>
  12.   <sql id="all_values_with_table_name">
  13.     sens_rbac_permission.id, sens_rbac_permission.`name`, sens_rbac_permission.permission
  14.   </sql>
  15.   <sql id="tb">`sens_rbac_permission`</sql>
  16.   <sql id="all_values">
  17.         #{id}, #{name}, #{permission}
  18.   </sql>
  19.   <select id="findByRoleId" resultType="com.liuyanzhao.sens.entity.Permission">
  20.     select
  21.     <include refid="all_values_with_table_name"/>
  22.     FROM<include refid="tb"/>, sens_rbac_role_permission_ref
  23.     where sens_rbac_role_permission_ref.role_id = #{value} AND
  24.     sens_rbac_permission.id = sens_rbac_role_permission_ref.permission_id
  25.   </select>
  26.   <select id="findAll" resultType="com.liuyanzhao.sens.entity.Permission">
  27.     SELECT <include refid="all_columns"/>
  28.     FROM <include refid="tb"/>
  29.   </select>
  30. </mapper>

 

备注:

关于UserRoleRefMapper.xml 和 RolePermissionRefMapper.xml 本文没有涉及到,不贴了

 

4. Service 接口

UserService.java

  1. package com.liuyanzhao.sens.service;
  2. import com.baomidou.mybatisplus.plugins.Page;
  3. import com.liuyanzhao.sens.entity.User;
  4. import java.util.Date;
  5. /**
  6.  * <pre>
  7.  *     用户业务逻辑接口
  8.  * </pre>
  9.  *
  10.  * @author : saysky
  11.  * @date : 2017/11/14
  12.  */
  13. public interface UserService {
  14.     /**
  15.      * 新增/修改用户
  16.      *
  17.      * @param user user
  18.      * @return Role
  19.      */
  20.     User saveByUser(User user);
  21.     /**
  22.      * 根据用户名获得用户
  23.      *
  24.      * @param userName 用户名
  25.      * @return 用户
  26.      */
  27.     User findByUserName(String userName);
  28.     /**
  29.      * 根据邮箱查找用户
  30.      *
  31.      * @param userEmail 邮箱
  32.      * @return User
  33.      */
  34.     User findByEmail(String userEmail);
  35.     /**
  36.      * 根据用户Id获得用户
  37.      *
  38.      * @param userId 用户名
  39.      * @return 用户
  40.      */
  41.     User findByUserId(Long userId);
  42.     /**
  43.      * 修改禁用状态
  44.      *
  45.      * @param enable enable
  46.      */
  47.     void updateUserLoginEnable(User user, String enable);
  48.     /**
  49.      * 修改最后登录时间
  50.      *
  51.      * @param lastDate 最后登录时间
  52.      * @return User
  53.      */
  54.     User updateUserLoginLast(User user, Date lastDate);
  55.     /**
  56.      * 增加登录错误次数
  57.      *
  58.      * @return 登录错误次数
  59.      */
  60.     Integer updateUserLoginError(User user);
  61.     /**
  62.      * 修改用户的登录状态为正常
  63.      *
  64.      * @return User
  65.      */
  66.     User updateUserLoginNormal(User user);
  67. }

 

RoleService.java

  1. package com.liuyanzhao.sens.service;
  2. import com.liuyanzhao.sens.entity.Role;
  3. import com.liuyanzhao.sens.entity.User;
  4. import java.util.List;
  5. /**
  6.  * <pre>
  7.  *     角色逻辑接口
  8.  * </pre>
  9.  *
  10.  * @author : saysky
  11.  * @date : 2017/11/14
  12.  */
  13. public interface RoleService {
  14.     /**
  15.      * 新增/修改角色
  16.      *
  17.      * @param role role
  18.      * @return Role
  19.      */
  20.     Role saveByRole(Role role);
  21.     /**
  22.      * 根据编号删除
  23.      *
  24.      * @param roleId roleId
  25.      * @return Role
  26.      */
  27.     void removeByRoleId(Integer roleId);
  28.     /**
  29.      * 删除某个用户的所有关联
  30.      *
  31.      * @param userId 用户Id
  32.      */
  33.     void removeByUserId(Long userId);
  34.     /**
  35.      * 根据编号查询单个权限
  36.      *
  37.      * @param roleId roleId
  38.      * @return Role
  39.      */
  40.     Role findByRoleId(Integer roleId);
  41.     /**
  42.      * 根据编号查询单个权限
  43.      *
  44.      * @param roleName roleName
  45.      * @return Role
  46.      */
  47.     Role findByRoleName(String roleName);
  48.     /**
  49.      * 根据用户Id获得角色列表
  50.      *
  51.      * @param userId 用户Id
  52.      * @return 角色列表
  53.      */
  54.     List<Role> listRolesByUserId(Long userId);
  55.     /**
  56.      * 获得所有的角色
  57.      *
  58.      * @return 角色列表
  59.      */
  60.     List<Role> findAll();
  61. }

 

PermissionService.java

  1. package com.liuyanzhao.sens.service;
  2. import com.liuyanzhao.sens.entity.Permission;
  3. import java.util.List;
  4. /**
  5.  * <pre>
  6.  *     权限逻辑接口
  7.  * </pre>
  8.  *
  9.  * @author : saysky
  10.  * @date : 2017/11/14
  11.  */
  12. public interface PermissionService {
  13.     /**
  14.      * 新增/修改权限
  15.      *
  16.      * @param permission permission
  17.      * @return Permission
  18.      */
  19.     Permission saveByPermission(Permission permission);
  20.     /**
  21.      * 根据编号删除
  22.      *
  23.      * @param permissionId permissionId
  24.      * @return Permission
  25.      */
  26.     void removeByPermissionId(Integer permissionId);
  27.     /**
  28.      * 根据编号查询单个权限
  29.      *
  30.      * @param permissionId permissionId
  31.      * @return Permission
  32.      */
  33.     Permission findByPermissionId(Integer permissionId);
  34.     /**
  35.      * 根据角色Id获得权限列表
  36.      *
  37.      * @param roleId 角色Id
  38.      * @return 权限列表
  39.      */
  40.     List<Permission> listPermissionsByRoleId(Integer roleId);
  41. }

 

5.Service 实现

UserServiceImpl.java

  1. package com.liuyanzhao.sens.service.impl;
  2. import com.baomidou.mybatisplus.plugins.Page;
  3. import com.liuyanzhao.sens.entity.Role;
  4. import com.liuyanzhao.sens.mapper.UserMapper;
  5. import com.liuyanzhao.sens.entity.User;
  6. import com.liuyanzhao.sens.model.enums.CommentStatusEnum;
  7. import com.liuyanzhao.sens.model.enums.TrueFalseEnum;
  8. import com.liuyanzhao.sens.model.enums.UserStatusEnum;
  9. import com.liuyanzhao.sens.service.RoleService;
  10. import com.liuyanzhao.sens.service.UserService;
  11. import com.liuyanzhao.sens.utils.RedisUtil;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.cache.annotation.CacheEvict;
  14. import org.springframework.cache.annotation.Cacheable;
  15. import org.springframework.stereotype.Service;
  16. import org.springframework.transaction.annotation.Transactional;
  17. import java.util.Collections;
  18. import java.util.Date;
  19. import java.util.List;
  20. import java.util.Objects;
  21. /**
  22.  * <pre>
  23.  *     用户业务逻辑实现类
  24.  * </pre>
  25.  *
  26.  * @author : saysky
  27.  * @date : 2017/11/14
  28.  */
  29. @Service
  30. public class UserServiceImpl implements UserService {
  31.     private static final String USERS_CACHE_NAME = "users";
  32.     @Autowired(required = false)
  33.     private UserMapper userMapper;
  34.     @Autowired(required = false)
  35.     private RoleService roleService;
  36.     @Override
  37.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  38.     public User saveByUser(User user) {
  39.         if (user != null && user.getUserId() != null) {
  40.             userMapper.updateById(user);
  41.         } else {
  42.             userMapper.insert(user);
  43.         }
  44.         return user;
  45.     }
  46.     @Override
  47.     @Cacheable(value = USERS_CACHE_NAME, key = "'users_name_'+#userName", unless = "#result == null")
  48.     public User findByUserName(String userName) {
  49.         return userMapper.findByUserName(userName);
  50.     }
  51.     @Override
  52.     @Cacheable(value = USERS_CACHE_NAME, key = "'users_email_'+#userEmail", unless = "#result == null")
  53.     public User findByEmail(String userEmail) {
  54.         return userMapper.findByUserEmail(userEmail);
  55.     }
  56.     @Override
  57.     @Cacheable(value = USERS_CACHE_NAME, key = "'users_id_'+#userName", unless = "#result == null")
  58.     public User findByUserId(Long userId) {
  59.         return userMapper.findByUserId(userId);
  60.     }
  61.     @Override
  62.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  63.     public void updateUser(User user) {
  64.         userMapper.updateById(user);
  65.     }
  66.     /**
  67.      * 修改禁用状态
  68.      *
  69.      * @param enable enable
  70.      */
  71.     @Override
  72.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  73.     public void updateUserLoginEnable(User user, String enable) {
  74.         //如果是修改为正常, 重置错误次数
  75.         if (Objects.equals(TrueFalseEnum.TRUE.getDesc(), enable)) {
  76.             user.setLoginError(0);
  77.         }
  78.         user.setLoginEnable(enable);
  79.         this.updateUser(user);
  80.     }
  81.     /**
  82.      * 修改最后登录时间
  83.      *
  84.      * @param lastDate 最后登录时间
  85.      * @return User
  86.      */
  87.     @Override
  88.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  89.     public User updateUserLoginLast(User user, Date lastDate) {
  90.         user.setLoginLast(lastDate);
  91.         this.updateUser(user);
  92.         return user;
  93.     }
  94.     /**
  95.      * 增加登录错误次数
  96.      *
  97.      * @return 登录错误次数
  98.      */
  99.     @Override
  100.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  101.     public Integer updateUserLoginError(User user) {
  102.         user.setLoginError((user.getLoginError() == null ? 0 : user.getLoginError()) + 1);
  103.         this.updateUser(user);
  104.         return user.getLoginError();
  105.     }
  106.     /**
  107.      * 修改用户的状态为正常
  108.      *
  109.      * @return User
  110.      */
  111.     @Override
  112.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  113.     public User updateUserLoginNormal(User user) {
  114.         user.setLoginEnable(TrueFalseEnum.TRUE.getDesc());
  115.         user.setLoginError(0);
  116.         user.setLoginLast(new Date());
  117.         this.updateUser(user);
  118.         return user;
  119.     }
  120.     @Override
  121.     @CacheEvict(value = USERS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  122.     public void updateUserStatus(Long userId, Integer status) {
  123.         User user = findByUserId(userId);
  124.         if (user != null) {
  125.             user.setStatus(status);
  126.             userMapper.updateById(user);
  127.         }
  128.     }
  129. }

 

RoleServiceImpl.java

  1. package com.liuyanzhao.sens.service.impl;
  2. import com.liuyanzhao.sens.entity.Role;
  3. import com.liuyanzhao.sens.mapper.RoleMapper;
  4. import com.liuyanzhao.sens.service.RoleService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheEvict;
  7. import org.springframework.cache.annotation.Cacheable;
  8. import org.springframework.stereotype.Service;
  9. import java.util.List;
  10. /**
  11.  * <pre>
  12.  *     角色业务逻辑实现类
  13.  * </pre>
  14.  *
  15.  * @author : saysky
  16.  * @date : 2017/11/14
  17.  */
  18. @Service
  19. public class RoleServiceImpl implements RoleService {
  20.     private static final String ROLES_CACHE_NAME = "roles";
  21.     @Autowired(required = false)
  22.     private RoleMapper roleMapper;
  23.     @Override
  24.     @CacheEvict(value = ROLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
  25.     public Role saveByRole(Role role) {
  26.         if (role != null && role.getId() != null) {
  27.             roleMapper.updateById(role);
  28.         } else {
  29.             roleMapper.insert(role);
  30.         }
  31.         return role;
  32.     }
  33.     @Override
  34.     @CacheEvict(value = ROLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
  35.     public void removeByRoleId(Integer roleId) {
  36.         roleMapper.deleteById(roleId);
  37.     }
  38.     @Override
  39.     @CacheEvict(value = ROLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
  40.     public void removeByUserId(Long userId) {
  41.         roleMapper.deleteByUserId(userId);
  42. }
  43.     @Override
  44.     @Cacheable(value = ROLES_CACHE_NAME, key = "'roles_id_'+#roleId", unless = "#result == null")
  45.     public Role findByRoleId(Integer roleId) {
  46.         return roleMapper.selectById(roleId);
  47.     }
  48.     @Override
  49.     @Cacheable(value = ROLES_CACHE_NAME, key = "'roles_name_'+#roleName", unless = "#result == null")
  50.     public Role findByRoleName(String roleName) {
  51.         return roleMapper.findByRoleName(roleName);
  52.     }
  53.     @Override
  54.     @Cacheable(value = ROLES_CACHE_NAME, key = "'roles_uid_'+#userId", unless = "#result == null")
  55.     public List<Role> listRolesByUserId(Long userId) {
  56.         return roleMapper.findByUserId(userId);
  57.     }
  58.     @Override
  59.     @Cacheable(value = ROLES_CACHE_NAME, key = "'roles_all'")
  60.     public List<Role> findAll() {
  61.         //获得角色
  62.         List<Role> roles = roleMapper.findAll();
  63.         //封装count
  64.         roles.forEach(role -> role.setCount(roleMapper.countUserByRoleId(role.getId())));
  65.         return roles;
  66.     }
  67. }

 

PermissionServiceImpl.java

  1. package com.liuyanzhao.sens.service;
  2. import com.liuyanzhao.sens.entity.Permission;
  3. import java.util.List;
  4. /**
  5.  * <pre>
  6.  *     权限逻辑接口
  7.  * </pre>
  8.  *
  9.  * @author : saysky
  10.  * @date : 2017/11/14
  11.  */
  12. public interface PermissionService {
  13.     /**
  14.      * 新增/修改权限
  15.      *
  16.      * @param permission permission
  17.      * @return Permission
  18.      */
  19.     Permission saveByPermission(Permission permission);
  20.     /**
  21.      * 根据编号删除
  22.      *
  23.      * @param permissionId permissionId
  24.      * @return Permission
  25.      */
  26.     void removeByPermissionId(Integer permissionId);
  27.     /**
  28.      * 根据编号查询单个权限
  29.      *
  30.      * @param permissionId permissionId
  31.      * @return Permission
  32.      */
  33.     Permission findByPermissionId(Integer permissionId);
  34.     /**
  35.      * 根据角色Id获得权限列表
  36.      *
  37.      * @param roleId 角色Id
  38.      * @return 权限列表
  39.      */
  40.     List<Permission> listPermissionsByRoleId(Integer roleId);
  41. }

 

三、整合 Shiro

1.MyShiroRealm.java

  1. package com.liuyanzhao.sens.config;
  2. import cn.hutool.core.date.DateUnit;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.lang.Validator;
  5. import cn.hutool.core.util.ObjectUtil;
  6. import cn.hutool.extra.servlet.ServletUtil;
  7. import cn.hutool.http.HtmlUtil;
  8. import com.liuyanzhao.sens.entity.Permission;
  9. import com.liuyanzhao.sens.entity.Role;
  10. import com.liuyanzhao.sens.entity.User;
  11. import com.liuyanzhao.sens.model.dto.JsonResult;
  12. import com.liuyanzhao.sens.model.dto.LogsRecord;
  13. import com.liuyanzhao.sens.model.enums.CommonParamsEnum;
  14. import com.liuyanzhao.sens.model.enums.ResultCodeEnum;
  15. import com.liuyanzhao.sens.model.enums.TrueFalseEnum;
  16. import com.liuyanzhao.sens.service.PermissionService;
  17. import com.liuyanzhao.sens.service.RoleService;
  18. import com.liuyanzhao.sens.service.UserService;
  19. import com.liuyanzhao.sens.utils.LocaleMessageUtil;
  20. import com.liuyanzhao.sens.utils.Md5Util;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.apache.commons.lang3.StringUtils;
  23. import org.apache.shiro.authc.*;
  24. import org.apache.shiro.authz.AuthorizationInfo;
  25. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  26. import org.apache.shiro.realm.AuthorizingRealm;
  27. import org.apache.shiro.subject.PrincipalCollection;
  28. import org.apache.shiro.util.ByteSource;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import java.util.Date;
  31. import java.util.List;
  32. /**
  33.  * 默认的realm
  34.  *
  35.  * @author 言曌
  36.  * @date 2018/9/1 上午10:47
  37.  */
  38. @Slf4j
  39. public class MyShiroRealm extends AuthorizingRealm {
  40.     @Autowired
  41.     private UserService userService;
  42.     @Autowired
  43.     private RoleService roleService;
  44.     @Autowired
  45.     private PermissionService permissionService;
  46.     @Autowired
  47.     private LocaleMessageUtil localeMessageUtil;
  48.     /**
  49.      * 认证信息(身份验证) Authentication 是用来验证用户身份
  50.      */
  51.     @Override
  52.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  53.         log.info("认证-->MyShiroRealm.doGetAuthenticationInfo()");
  54.         //1.验证用户名
  55.         User user = null;
  56.         String loginName = (String) token.getPrincipal();
  57.         if (Validator.isEmail(loginName)) {
  58.             user = userService.findByEmail(loginName);
  59.         } else {
  60.             user = userService.findByUserName(loginName);
  61.         }
  62.         if (user == null) {
  63.             //用户不存在
  64.             log.info("用户不存在! 登录名:{}, 密码:{}", loginName, token.getCredentials());
  65.             return null;
  66.         }
  67.         //2.首先判断是否已经被禁用已经是否已经过了10分钟
  68.         Date loginLast = DateUtil.date();
  69.         if (null != user.getLoginLast()) {
  70.             loginLast = user.getLoginLast();
  71.         }
  72.         Long between = DateUtil.between(loginLast, DateUtil.date(), DateUnit.MINUTE);
  73.         if (StringUtils.equals(user.getLoginEnable(), TrueFalseEnum.FALSE.getDesc()) && (between < CommonParamsEnum.TEN.getValue())) {
  74.             log.info("账号已锁定! 登录名:{}, 密码:{}", loginName, token.getCredentials());
  75.             throw new LockedAccountException("账号被锁定");
  76.         }
  77.         userService.updateUserLoginLast(user, DateUtil.date());
  78.         //3.封装authenticationInfo,准备验证密码
  79.         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
  80.                 user, // 用户名
  81.                 user.getUserPass(), // 密码
  82.                 ByteSource.Util.bytes("sens"), // 盐
  83.                 getName() // realm name
  84.         );
  85.         System.out.println("realName:" + getName());
  86.         return authenticationInfo;
  87.     }
  88.     @Override
  89.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  90.         log.info("授权-->MyShiroRealm.doGetAuthorizationInfo()");
  91.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  92.         User user = (User) principals.getPrimaryPrincipal();
  93.         List<Role> roles = roleService.listRolesByUserId(user.getUserId());
  94.         for (Role role : roles) {
  95.             authorizationInfo.addRole(role.getRole());
  96.             List<Permission> permissions = permissionService.listPermissionsByRoleId(role.getId());
  97.             for (Permission p : permissions) {
  98.                 authorizationInfo.addStringPermission(p.getPermission());
  99.             }
  100.         }
  101.         return authorizationInfo;
  102.     }
  103. }

 

上面一个方法是自定义认证方法,查询用户是否存在,然后把密码等信息放到 authenticationInfo 里,shiro 然后进行验证。

下面这个方法是被已登录用户封装角色列表和权限列表。

 

2.ShiroConfig.java

  1. package com.liuyanzhao.sens.config;
  2. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  3. import org.apache.shiro.mgt.SecurityManager;
  4. import org.apache.shiro.realm.Realm;
  5. import org.apache.shiro.spring.LifecycleBeanPostProcessor;
  6. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  7. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  8. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  9. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import org.springframework.context.annotation.DependsOn;
  13. import java.util.ArrayList;
  14. import java.util.LinkedHashMap;
  15. import java.util.List;
  16. import java.util.Map;
  17. /**
  18.  * @author 言曌
  19.  * @date 2018/8/20 上午6:19
  20.  */
  21. @Configuration
  22. public class ShiroConfig {
  23.     @Bean
  24.     public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
  25.         System.out.println("ShiroConfiguration.shirFilter()");
  26.         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  27.         shiroFilterFactoryBean.setSecurityManager(securityManager);
  28.         //拦截器.
  29.         Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
  30.         // 配置不会被拦截的链接 顺序判断
  31.         filterChainDefinitionMap.put("/static/**""anon");
  32.         filterChainDefinitionMap.put("/upload/**""anon");
  33.         filterChainDefinitionMap.put("/favicon.ico""anon");
  34.         filterChainDefinitionMap.put("/favicon.ico""anon");
  35.         filterChainDefinitionMap.put("/admin/login""anon");
  36.         filterChainDefinitionMap.put("/admin/getLogin""anon");
  37.         //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
  38.         filterChainDefinitionMap.put("/logout""logout");
  39.         //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
  40.         //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
  41.         filterChainDefinitionMap.put("/admin/**""authc");
  42.         filterChainDefinitionMap.put("/backup/**""authc");
  43.         filterChainDefinitionMap.put("/**""anon");
  44.         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  45.         // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
  46.         shiroFilterFactoryBean.setLoginUrl("/admin/login");
  47.         // 登录成功后要跳转的链接
  48.         shiroFilterFactoryBean.setSuccessUrl("/");
  49.         //未授权界面;
  50.         shiroFilterFactoryBean.setUnauthorizedUrl("/403");
  51.         return shiroFilterFactoryBean;
  52.     }
  53.     @Bean
  54.     public SecurityManager securityManager() {
  55.         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  56.         securityManager.setRealm(myShiroRealm());
  57.         return securityManager;
  58.     }
  59.     /**
  60.      * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
  61.      *
  62.      * @return MyShiroRealm
  63.      */
  64.     @Bean
  65.     public MyShiroRealm myShiroRealm() {
  66.         MyShiroRealm myShiroRealm = new MyShiroRealm();
  67.         myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
  68.         return myShiroRealm;
  69.     }
  70.     /**
  71.      * 凭证匹配器
  72.      * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
  73.      *  所以我们需要修改下doGetAuthenticationInfo中的代码;
  74.      * )
  75.      * @return
  76.      */
  77.     @Bean
  78.     public HashedCredentialsMatcher hashedCredentialsMatcher(){
  79.         HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
  80.         hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
  81.         hashedCredentialsMatcher.setHashIterations(2);//散列的次数,md5(md5("xxx"))
  82.         return hashedCredentialsMatcher;
  83.     }
  84.     /**
  85.      *  开启shiro aop注解支持,不开启无法使用 shiro 的注解.
  86.      *  使用代理方式;所以需要开启代码支持;
  87.      * @param securityManager
  88.      * @return
  89.      */
  90.     /** * Shiro生命周期处理器 * @return */
  91.     @Bean
  92.     public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
  93.         return new LifecycleBeanPostProcessor();
  94.     }
  95.     @Bean
  96.     @DependsOn({"lifecycleBeanPostProcessor"})
  97.     public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
  98.         DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
  99.         advisorAutoProxyCreator.setProxyTargetClass(true);
  100.         return advisorAutoProxyCreator;
  101.     }
  102.     @Bean
  103.     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
  104.         AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  105.         authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
  106.         return authorizationAttributeSourceAdvisor;
  107.     }
  108. }

 

四、登录和退出

下面是登录的后台代码

主要是做一个 subject.login() 的操作,然后 try catch,根据抛的异常,返回指定的信息或者跳转。

这里说明一下,登录成功后,不需要添加 session,shiro 有自己的 SessionDao 创建 session,但是那个 key,可能不知道。

后台获得用户直接从 subject.getPrincipal(); 里拿,前台可以用对应的模板引擎取,或者向后台发请求获得当前用户,建议不用自己弄 session,容易出现两个 session 过期时间不同,尤其是记住密码后。

 

1.登录代码

  1. /**
  2.    * 验证登录信息
  3.    *
  4.    * @param loginName 登录名:邮箱/用户名
  5.    * @param loginPwd  loginPwd 密码
  6.    * @return JsonResult JsonResult
  7.    */
  8.   @PostMapping(value = "/doLogin")
  9.   @ResponseBody
  10.   public JsonResult getLogin(@ModelAttribute("loginName") String loginName,
  11.                              @ModelAttribute("loginPwd") String loginPwd) {
  12.       Subject subject = SecurityUtils.getSubject();
  13.       UsernamePasswordToken token = new UsernamePasswordToken(loginName, loginPwd);
  14.       try {
  15.           subject.login(token);
  16.           if (subject.isAuthenticated()) {
  17.               //登录成功,修改登录错误次数为0
  18.               User user = (User) subject.getPrincipal();
  19.               userService.updateUserLoginNormal(user);
  20.               return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), "登录成功!");
  21.           }
  22.       } catch (UnknownAccountException e) {
  23.           log.info("UnknownAccountException -- > 账号不存在:");
  24.           return new JsonResult(ResultCodeEnum.FAIL.getCode(), "用户不存在!"));
  25.       } catch (IncorrectCredentialsException e) {
  26.           //更新失败次数
  27.           User user;
  28.           if (Validator.isEmail(loginName)) {
  29.               user = userService.findByEmail(loginName);
  30.           } else {
  31.               user = userService.findByUserName(loginName);
  32.           }
  33.           if (user != null) {
  34.               Integer errorCount = userService.updateUserLoginError(user);
  35.               //超过五次禁用账户
  36.               if (errorCount >= CommonParamsEnum.FIVE.getValue()) {
  37.                   userService.updateUserLoginEnable(user, TrueFalseEnum.FALSE.getDesc());
  38.               }
  39.               int rest = 5 - errorCount;
  40.               return new JsonResult(ResultCodeEnum.FAIL.getCode(), "密码错误,你还可以尝试 [" + rest + "] 次!"));
  41.           }
  42.       } catch (LockedAccountException e) {
  43.           log.info("LockedAccountException -- > 账号被锁定");
  44.           return new JsonResult(ResultCodeEnum.FAIL.getCode(), "账号被锁定,十分钟后再来!");
  45.       } catch (Exception e) {
  46.           log.info(e.getMessage());
  47.       }
  48.       return new JsonResult(ResultCodeEnum.FAIL.getCode(), "发送错误!");
  49.   }

 

2.退出代码

  1. /**
  2.    * 退出登录
  3.    *
  4.    * @return 重定向到/admin/login
  5.    */
  6.   @GetMapping(value = "/logOut")
  7.   public String logOut() {
  8.       Subject subject = SecurityUtils.getSubject();
  9.       User user = (User) subject.getPrincipal();
  10.       subject.logout();
  11.       log.info("用户[{}]退出登录", user.getUserName());
  12.       return "redirect:/admin/login";
  13.   }

 

七、权限控制

主要是在方法上加 @RequiresPermissions 注解或者 @RequiresRoles 注解,也可以在类上加(那就是整个类里的所有方法必须要有这个权限)

下面以标签控制器为例

  1. package com.liuyanzhao.sens.web.controller.admin;
  2. import com.liuyanzhao.sens.entity.Tag;
  3. import com.liuyanzhao.sens.model.dto.JsonResult;
  4. import com.liuyanzhao.sens.model.enums.ResultCodeEnum;
  5. import com.liuyanzhao.sens.service.TagService;
  6. import com.liuyanzhao.sens.utils.LocaleMessageUtil;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.shiro.authz.annotation.RequiresPermissions;
  9. import org.apache.shiro.authz.annotation.RequiresRoles;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.stereotype.Controller;
  12. import org.springframework.ui.Model;
  13. import org.springframework.web.bind.annotation.*;
  14. import java.util.List;
  15. /**
  16.  * <pre>
  17.  *     后台标签管理控制器
  18.  * </pre>
  19.  *
  20.  * @author : saysky
  21.  * @date : 2017/12/10
  22.  */
  23. @Slf4j
  24. @Controller
  25. @RequestMapping(value = "/admin/tag")
  26. public class TagController {
  27.     @Autowired
  28.     private TagService tagService;
  29.     @Autowired
  30.     private LocaleMessageUtil localeMessageUtil;
  31.     /**
  32.      * 渲染标签管理页面
  33.      *
  34.      * @return 模板路径admin/admin_tag
  35.      */
  36.     @GetMapping
  37.     @RequiresPermissions("tag:list")
  38.     public String tags(Model model) {
  39.         List<Tag> tags = tagService.findAllTags();
  40.         model.addAttribute("tags", tags);
  41.         return "admin/admin_tag";
  42.     }
  43.     /**
  44.      * 新增/修改标签
  45.      *
  46.      * @param tag tag
  47.      * @return 重定向到/admin/tag
  48.      */
  49.     @PostMapping(value = "/save")
  50.     @RequiresPermissions("tag:save")
  51.     public String saveTag(@ModelAttribute Tag tag) {
  52.         try {
  53.             tagService.saveByTag(tag);
  54.         } catch (Exception e) {
  55.             log.error("新增/修改标签失败:{}", e.getMessage());
  56.         }
  57.         return "redirect:/admin/tag";
  58.     }
  59.     /**
  60.      * 验证是否存在该路径
  61.      *
  62.      * @param tagUrl 标签路径名
  63.      * @return true:不存在,false:已存在
  64.      */
  65.     @GetMapping(value = "/checkUrl")
  66.     @ResponseBody
  67.     @RequiresPermissions("tag:url:check")
  68.     public JsonResult checkTagUrlExists(@RequestParam("tagUrl") String tagUrl) {
  69.         Tag tag = tagService.findByTagUrl(tagUrl);
  70.         if (null != tag) {
  71.             return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.url-is-exists"));
  72.         }
  73.         return new JsonResult(ResultCodeEnum.SUCCESS.getCode(), "");
  74.     }
  75.     /**
  76.      * 删除标签
  77.      *
  78.      * @param tagId 标签Id
  79.      * @return JsonResult
  80.      */
  81.     @GetMapping(value = "/remove")
  82.     @ResponseBody
  83.     @RequiresPermissions("tag:delete")
  84.     public JsonResult checkDelete(@RequestParam("tagId") Long tagId) {
  85.         tagService.removeByTagId(tagId);
  86.         return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-success"));
  87.     }
  88.     /**
  89.      * 跳转到修改标签页面
  90.      *
  91.      * @param model model
  92.      * @param tagId 标签编号
  93.      * @return 模板路径admin/admin_tag
  94.      */
  95.     @GetMapping(value = "/edit")
  96.     @RequiresPermissions("tag:edit")
  97.     public String toEditTag(Model model, @RequestParam("tagId") Long tagId) {
  98.         //当前修改的标签
  99.         Tag tag = tagService.findByTagId(tagId);
  100.         model.addAttribute("updateTag", tag);
  101.         //所有标签
  102.         List<Tag> tags = tagService.findAllTags();
  103.         model.addAttribute("tags", tags);
  104.         return "admin/admin_tag";
  105.     }
  106. }

 

本文介绍至此完毕,核心部分为 ShiroRealm.java 和 ShiroConfig.java 两个类

 

 

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
言曌

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:2   其中:访客  2   博主  0

    • avatar 访客

      文章不错支持一下吧

      • avatar 刘慧斌

        springboot 整合shiro有Git链接吗,想学习下