Shiro是一个非常不错的权限框架,它提供了登录和权限验证功能,如果想去了解它的话可以去Shiro官网学习 点击打开
1.创建数据库脚本
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for module
-- ----------------------------
DROP TABLE IF EXISTS `module`;
CREATE TABLE `module` (
`mid` int(11) NOT NULL AUTO_INCREMENT,
`mname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`mid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of module
-- ----------------------------
INSERT INTO `module` VALUES (1, 'add');
INSERT INTO `module` VALUES (2, 'delete');
INSERT INTO `module` VALUES (3, 'query');
INSERT INTO `module` VALUES (4, 'update');
-- ----------------------------
-- Table structure for module_role
-- ----------------------------
DROP TABLE IF EXISTS `module_role`;
CREATE TABLE `module_role` (
`rid` int(11) NULL DEFAULT NULL,
`mid` int(11) NULL DEFAULT NULL,
INDEX `rid`(`rid`) USING BTREE,
INDEX `mid`(`mid`) USING BTREE,
CONSTRAINT `mid` FOREIGN KEY (`mid`) REFERENCES `module` (`mid`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `rid` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of module_role
-- ----------------------------
INSERT INTO `module_role` VALUES (1, 1);
INSERT INTO `module_role` VALUES (1, 2);
INSERT INTO `module_role` VALUES (1, 3);
INSERT INTO `module_role` VALUES (1, 4);
INSERT INTO `module_role` VALUES (2, 1);
INSERT INTO `module_role` VALUES (2, 3);
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`rname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`rid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'admin');
INSERT INTO `role` VALUES (2, 'customer');
INSERT INTO `role` VALUES (3, NULL);
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'hlhdidi', '123');
INSERT INTO `user` VALUES (2, 'xyycici', '1992');
INSERT INTO `user` VALUES (3, 'sujin', '123');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`uid` int(11) NULL DEFAULT NULL,
`rid` int(11) NULL DEFAULT NULL,
INDEX `u_fk`(`uid`) USING BTREE,
INDEX `r_fk`(`rid`) USING BTREE,
CONSTRAINT `r_fk` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `u_fk` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (2, 2);
INSERT INTO `user_role` VALUES (3, 3);
SET FOREIGN_KEY_CHECKS = 1;
当新添加一个用户时,只需要配置权限即可,module_role表中已经配置了什么权限拥有什么样的功能
SELECT u.*,r.*,m.* FROM user u inner join user_role ur on ur.uid=u.uid
inner join role r on r.rid=ur.rid
inner join module_role mr on mr.rid=r.rid
inner join module m on mr.mid=m.mid
WHERE username='hlhdidi'; -- xyycici用户已分配只要两个权限 add和query
2.pom.xml中添加Springboot集成shiro的相关依赖
<!-- shiro整合springboot所需相关依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>1.2.1</version>
</dependency>
<!--end.......-->
3.创建实体类
仅列出关键实体类,其他实体类无需改动
用户
package com.king.s5.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
//用户
public class User implements Serializable{
private Integer uid;
private String username;
private String password;
private Set<Role> roles = new HashSet<>();
public User(Integer uid, String username, String password) {
this.uid = uid;
this.username = username;
this.password = password;
}
public User() {
super();
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
功能
package com.king.s5.model;
import java.util.HashSet;
import java.util.Set;
//功能
public class Module {
private Integer mid;
private String mname;
private Set<Role> roles;
public Module(Integer mid, String mname) {
this.mid = mid;
this.mname = mname;
}
public Module() {
super();
}
public Integer getMid() {
return mid;
}
public void setMid(Integer mid) {
this.mid = mid;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
权限
public class Role {
private Integer rid;
private String rname;
private Set<User> users = new HashSet<>();
private Set<Module> Modules = new HashSet<>();
public Role(Integer rid, String rname) {
this.rid = rid;
this.rname = rname;
}
public Role() {
super();
}
public Integer getRid() {
return rid;
}
public void setRid(Integer rid) {
this.rid = rid;
}
public String getRname() {
return rname;
}
public void setRname(String rname) {
this.rname = rname;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Set<Module> getModules() {
return Modules;
}
public void setModules(Set<Module> modules) {
Modules = modules;
}
}
4.编写持久层mapper.xml
userMapper.xml,本次只写到mapper层,不做service层(仅列出关键mapper.xml),其他xml无需改变
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.king.s5.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="com.king.s5.model.User" >
<constructor >
<idArg column="uid" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="username" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="password" jdbcType="VARCHAR" javaType="java.lang.String" />
</constructor>
</resultMap>
<resultMap type="com.king.s5.model.User" id="userMap">
<id property="uid" column="uid"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<collection property="roles" ofType="com.king.s5.model.Role">
<id property="rid" column="rid"/>
<result property="rname" column="rname"/>
<collection property="modules" ofType="com.king.s5.model.Module">
<id property="mid" column="mid"/>
<result property="mname" column="mname"/>
</collection>
</collection>
</resultMap>
<sql id="Base_Column_List" >
uid, username, password
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from user
where uid = #{uid,jdbcType=INTEGER}
</select>
<select id="queryUserName" parameterType="string" resultMap="userMap">
SELECT u.*,r.*,m.* FROM user u inner join user_role ur on ur.uid=u.uid
inner join role r on r.rid=ur.rid
inner join module_role mr on mr.rid=r.rid
inner join module m on mr.mid=m.mid
WHERE username=#{username};
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from user
where uid = #{uid,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.king.s5.model.User" >
insert into user (uid, username, password
)
values (#{uid,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="com.king.s5.model.User" >
insert into user
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="uid != null" >
uid,
</if>
<if test="username != null" >
username,
</if>
<if test="password != null" >
password,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="uid != null" >
#{uid,jdbcType=INTEGER},
</if>
<if test="username != null" >
#{username,jdbcType=VARCHAR},
</if>
<if test="password != null" >
#{password,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.king.s5.model.User" >
update user
<set >
<if test="username != null" >
username = #{username,jdbcType=VARCHAR},
</if>
<if test="password != null" >
password = #{password,jdbcType=VARCHAR},
</if>
</set>
where uid = #{uid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.king.s5.model.User" >
update user
set username = #{username,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR}
where uid = #{uid,jdbcType=INTEGER}
</update>
</mapper>
moduleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.king.s5.mapper.ModuleMapper" >
<resultMap id="BaseResultMap" type="com.king.s5.model.Module" >
<constructor >
<idArg column="mid" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="mname" jdbcType="VARCHAR" javaType="java.lang.String" />
</constructor>
</resultMap>
<sql id="Base_Column_List" >
mid, mname
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from module
where mid = #{mid,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from module
where mid = #{mid,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.king.s5.model.Module" >
insert into module (mid, mname)
values (#{mid,jdbcType=INTEGER}, #{mname,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.king.s5.model.Module" >
insert into module
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="mid != null" >
mid,
</if>
<if test="mname != null" >
mname,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="mid != null" >
#{mid,jdbcType=INTEGER},
</if>
<if test="mname != null" >
#{mname,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.king.s5.model.Module" >
update module
<set >
<if test="mname != null" >
mname = #{mname,jdbcType=VARCHAR},
</if>
</set>
where mid = #{mid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.king.s5.model.Module" >
update module
set mname = #{mname,jdbcType=VARCHAR}
where mid = #{mid,jdbcType=INTEGER}
</update>
</mapper>
5.添加shiro的工具类
认证授权工具类
package com.king.s5.shiro;
import com.king.s5.biz.IUserBiz;
import com.king.s5.mapper.UserMapper;
import com.king.s5.model.Module;
import com.king.s5.model.Role;
import com.king.s5.model.User;
import org.apache.shiro.authc.*;
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.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class AuthRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
//认证.登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;//获取用户输入的token
String username = utoken.getUsername();
User user = userMapper.queryUserName(username);
//放入shiro.调用CredentialsMatcher检验密码
return new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName());
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
//获取session中的用户
User user=(User) principal.fromRealm(this.getClass().getName()).iterator().next();
List<String> permissions=new ArrayList<>();
Set<Role> roles = user.getRoles();
if(roles.size()>0) {
for(Role role : roles) {
Set<Module> modules = role.getModules();
if(modules.size()>0) {
for(Module module : modules) {
permissions.add(module.getMname());
}
}
}
}
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//将权限放入shiro中.
info.addStringPermissions(permissions);
return info;
}
}
权限用户密码校验类
package com.king.s5.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
public class CredentialsMatcher extends SimpleCredentialsMatcher {
//校验
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
String inPassword = new String(utoken.getPassword());
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
//进行密码的比对
return this.equals(inPassword, dbPassword);
}
}
shiro配置类
package com.king.s5.shiro;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
/**
* shiro的配置类
* @author sujin
*
*/
@Configuration
public class ShiroConfiguration {
@Bean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
bean.setSecurityManager(manager);
//配置登录的url和登录成功的url
bean.setLoginUrl("/login");
bean.setSuccessUrl("/home");
//配置访问权限
LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
filterChainDefinitionMap.put("/login*", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/loginUser", "anon");
filterChainDefinitionMap.put("/client/test", "anon");
filterChainDefinitionMap.put("/assert/test", "anon");//添加白名单
filterChainDefinitionMap.put("/assert/get", "anon");//添加白名单
filterChainDefinitionMap.put("/assert/assertQuery", "anon");//添加白名单
filterChainDefinitionMap.put("/a", "anon");
filterChainDefinitionMap.put("/book/list", "anon");
filterChainDefinitionMap.put("/logout*","anon");
filterChainDefinitionMap.put("/jsp/error.jsp*","anon");
filterChainDefinitionMap.put("/jsp/login.jsp*","authc");
filterChainDefinitionMap.put("/*", "authc");//表示需要认证才可以访问
filterChainDefinitionMap.put("/**", "authc");//表示需要认证才可以访问
filterChainDefinitionMap.put("/*.*", "authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
//配置核心安全事务管理器
@Bean(name="securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
System.err.println("--------------shiro已经加载----------------");
DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
manager.setRealm(authRealm);
return manager;
}
//配置自定义的权限登录器
@Bean(name="authRealm")
public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
AuthRealm authRealm=new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
//配置自定义的密码比较器
@Bean(name="credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new CredentialsMatcher();
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
}
6.控制层controller
package com.king.s5.controller;
import com.king.s5.model.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/a")
public String a() {
return "a";
}
@RequestMapping("/loginUser")
public String loginUser(String username,String password,HttpSession session) {
//授权认证
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
//完成登录
subject.login(usernamePasswordToken);
//获得用户对象
User user=(User) subject.getPrincipal();
//存入session
session.setAttribute("user", user);
return "index";
} catch(Exception e) {
return "login";//返回登录页面
}
}
@RequestMapping("/logOut")
public String logOut(HttpSession session) {
Subject subject = SecurityUtils.getSubject();
subject.logout();
// session.removeAttribute("user");
return "login";
}
}
7.视图层jsp
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>登录</title>
</head>
<h1>欢迎登录!${user.username }</h1>
<form action="${pageContext.request.contextPath }/loginUser" method="post">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>登录</title>
</head>
<h1>欢迎${user.username }光临!请选择你的操作:</h1><br>
<ul>
<shiro:hasPermission name="add"><li>增加</li></shiro:hasPermission>
<shiro:hasPermission name="delete"><li>删除</li></shiro:hasPermission>
<shiro:hasPermission name="update"><li>修改</li></shiro:hasPermission>
<shiro:hasPermission name="query"><li>查询</li></shiro:hasPermission>
</ul>
<a href="${pageContext.request.contextPath }/logOut">点我注销</a>
</body>
</html>
8.shiro标签的使用
guest标签 | 验证当前用户是否为“访客”,即未认证(包含未记住)的用户 |
user标签 | 认证通过或已记住的用户 |
authenticated标签 | 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在 |
notAuthenticated标签 | 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户 |
principal 标签 | 输出当前用户信息,通常为登录帐号信息 |
hasRole标签 | 验证当前用户是否属于该角色 |
lacksRole标签 | 与hasRole标签逻辑相反,当用户不属于该角色时验证通过 |
hasAnyRole标签 | 验证当前用户是否属于以下任意一个角色 |
hasPermission标签 | 验证当前用户是否拥有指定权限 |
lacksPermission标签 | 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过 |
如果大家有什么问题,可以在下方留言,想要源码的可以到我的资源库下载 点击下载
--------------如果大家喜欢我的博客,可以点击左上角的关注哦。