SpringBoot+shiro+mybatis 实现权限登录
2.创建 spring boot 项目,用 maven 构建
==============================================================================================
创建实体类(User,Role,Permissions):
User:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
//用户对应的角色集合
private Role role;
}
=========================================================================
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private Integer id;
private String roleName;
}
================================================================================
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Permissions {
private Integer id;
private String permissionName;
private Role role;
}
我们需要知道三个实体类之间的关系,User 与 Role 一对一,Role 与 Permissions 一对一,当然也可以把它都写成多对多,这就需要去更改数据库文件,和实体类了。
=====================================================================================
下面只给出相关依赖源
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
===========================================================================================
就只需要创建一个 dao 层,一个服务层,需要记住要?添加注解?:
(1)mapper 配置文件(也可以使用注解形式):
<?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.example.csy.dao.UserMapper">
<select id="queryUserByUsername" resultMap="userRoleMap">
SELECT u.*,r.role_name FROM user
u, role
r
WHERE username = #{username} AND u.role_id = r.id;
</select>
<resultMap id="userRoleMap" type="com.example.csy.entity.User">
<id property="id" column="id"/>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<association property="role" javaType="com.example.csy.entity.Role">
<id property="id" column="id"></id>
<result property="roleName" column="role_name"></result>
</association>
</resultMap>
<select id="queryPermissionByUsername" resultMap="permissionRoleMap">
SELECT p.* ,r.role_name FROM user
u, role
r, permission
p
WHERE username = #{username} AND u.role_id = r.id AND p.role_id = r.id;
</select>
<resultMap id="permissionRoleMap" type="com.example.csy.entity.Permissions">
<id property="id" column="id"/>
<result property="permissionName" column="permission_name"></result>
<association property="role" javaType="com.example.csy.entity.Role">
<id property="id" column="id"></id>
<result property="roleName" column="role_name"></result>
</association>
</resultMap>
</mapper>
(2)DAO 层:
@Mapper
public interface UserMapper {
User queryUserByUsername(@Param("username") String username);
Permissions queryPermissionByUsername(@Param("username") String username);
}
(3)service 层:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User queryUserByUsername(String username) {
return userMapper.queryUserByUsername(username);
}
@Override
public Permissions queryPermissionByUsername(String username) {
return userMapper.queryPermissionByUsername(username);
}
}
弄到这里,我们的 mybatis+springboot 整合也基本结束,所以在测试类里测试一下:
@SpringBootTest
class CsyApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
User admin = userMapper.queryUserByUsername("admin");
System.out.println(admin.toString());
Permissions permission = userMapper.queryPermissionByUsername("admin");
System.out.println(permission.toString());
}
}
测试结果:
得到了查询结果
====================================================================================
前端页面:
在 html 页面我们整合了 Thymeleaf,使用了 Jquery,semantic,需要导包
index.html 代码:
在这里,如果是 User 就只能访问 A,Admin 能访问 A,B,superAdmin 能访问 A,B,C
<!DOCTYPE html>
<html lang="zh_CN"
xmlns:th="http://www.thymeleaf.org"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
<html lang="en">
<head>
<meta charset="UTF-8">
<title>信息管理平台-首页</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1"
/>
<title>首页</title>
<link
href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css"
rel="stylesheet"
/>
<link th:href="@{/css/index.css}" rel="stylesheet">
<script src="js/jquery-3.1.1.min.js"></script>
</head>
<body>
<div class="ui container">
<div class="ui secondary menu">
<a class="active item" th:href="@{/index}">
首页
</a>
<a class="active item" th:href="@{/about}">
关于
</a>
<div class="right menu">
<div shiro:notAuthenticated="">
<a class="item" th:href="@{/toLoginPage}">
<i class="address card icon"></i> 登录
</a>
</div>
<div shiro:authenticated="">
<a class="item">
<i class="address card icon"></i>
用户名:<span shiro:principal></span>
</a>
</div>
<div shiro:authenticated="">
<a class="item" th:href="@{/logout}">
<i class="address card icon"></i> 注销
</a>
</div>
</div>
</div>
<div class="ui stackable three column grid">
<div class="ui raised segments">
<div class="ui segment">
<a th:href="@{/levelA/a}">L-A-a</a>
</div>
<div class="ui segment">
<a th:href="@{/levelA/b}">L-A-b</a>
</div>
<div class="ui segment">
<a th:href="@{/levelA/c}">L-A-c</a>
</div>
</div>
</div>
<div class="column" shiro:hasAnyRoles="ADMIN,SUPER_ADMIN">
<div class="ui raised segments">
<div class="ui segment">
<a th:href="@{/levelB/a}">L-B-a</a>
</div>
<div class="ui segment">
<a th:href="@{/levelB/b}">L-B-b</a>
</div>
<div class="ui segment">
<a th:href="@{/levelB/c}">L-B-c</a>
</div>
</div>
</div>
<div class="column" shiro:hasRole="SUPER_ADMIN">
<div class="ui raised segments">
<div class="ui segment">
<a th:href="@{/levelC/a}">L-C-a</a>
</div>
<div class="ui segment">
<a th:href="@{/levelC/b}">L-C-b</a>
</div>
<div class="ui segment">
<a th:href="@{/levelC/c}">L-C-c</a>
</div>
</div>
</div>
</div>
<div class="ui stacked segment">
<div class="ui stackable three column grid">
<div class="column">
<p>
晚风吹起你鬓间的白发<br/>
抚平回忆留下的疤<br/>
你的眼中 明暗交杂 一笑生花<br/>
暮色遮住你蹒跚的步伐<br/>
走进床头藏起的画<br/>
画中的你 低着头说话<br/>
我仍感叹于世界之大
</p>
</div>
<div class="column">
<p>
也沉醉于儿时情话<br/>
不剩真假 不做挣扎 无谓笑话<br/>
我终将青春还给了她<br/>
连同指尖弹出的盛夏<br/>
心之所动 就随风去了<br/>
以爱之名 你还愿意吗<br/>
?
</p>
</div>
<div class="column">
<img class="ui medium circular image" src="images/001.jpg">
</div>
</div>
</div>
<div class="ui info message">
<div class="header">理想二旬不止</div>
<p>BWH_Steven</p>
</div>
</div>
</body>
</html>
=================================================================================
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
<head>
<meta charset="UTF-8">
<title>用户管理系统-登录</title>
<script src="js/jquery-3.1.1.min.js"></script>
<link
href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css"
rel="stylesheet"
/>
</head>
<body>
<h1>用户管理系统-登录</h1>
<div class="ui container" style="margin-top: 180px;">
<div style="text-align: center; margin-bottom: 20px;">
<h1 class="header">
登录
</h1>
</div>
<div class="ui three column stackable grid login-div">
<div class="column"></div>
<div class="column">
<form id="login" class="ui fluid form segment" th:action="@{/login}" method="post">
<div class="field">
<label class="">用户名</label>
<div class="ui left icon input">
<input type="text" name="username" placeholder=""/>
<i class="user icon"></i>
<div class="ui corner label">
<i class="icon asterisk"></i>
</div>
</div>
</div>
<div class="field">
<label class="">密码</label>
<div class="ui left icon input">
<input type="password" name="password" placeholder=""/>
<i class="lock icon"></i>
<div class="ui corner label">
<i class="icon asterisk"></i>
</div>
</div>
</div>
<div class="inline field">
<div class="ui checkbox">
<input type="checkbox" name="terms"/>
<label>记住密码</label>
</div>
</div>
<div class="inline field">
<input type="submit" class="ui blue submit button">
</div>
</form>
</div>
<div class="column"></div>
</div>
</div>
</body>
</html>
success.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户管理系统-成功</title>
</head>
<body>
<h2>登录成功</h2>
<a href="/index">返回主页</a>
</body>
</html>
===================================================================================
================================================================================
我们需要自定义,认证和授权:
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
/**
@MethodName doGetAuthorizationInfo 授权操作
@Description 权限配置类
@Param [principalCollection]
@Return AuthorizationInfo
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取用户名信息
String username = (String) principalCollection.getPrimaryPrincipal();
// 创建一个简单授权验证信息
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 给这个用户设置从 role 表获取到的角色信息
authorizationInfo.addRole(userMapper.queryUserByUsername(username).getRole().getRoleName());
//给这个用户设置从 permission 表获取的权限信息
authorizationInfo.addStringPermission(userMapper.queryPermissionByUsername(username).getPermissionName());
return authorizationInfo;
}
/**
@MethodName doGetAuthenticationInfo 身份验证
@Description 认证配置类
@Param [authenticationToken]
@Return AuthenticationInfo
@Author WangShiLin
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 根据在接受前台数据创建的 Token 获取用户名
String username = (String) authenticationToken.getPrincipal();
// UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
// System.out.println(userToken.getPrincipal());
// System.out.println(userToken.getUsername());
// System.out.println(userToken.getPassword());
// 通过用户名查询相关的用户信息(实体)
User user = userMapper.queryUserByUsername(username);
if (user != null) {
// 存入 Session,可选
SecurityUtils.getSubject().getSession().setAttribute("user", user);
// 密码认证的工作,Shiro 来做
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "userRealm");
return authenticationInfo;
} else {
// 返回 null 即会抛异常
return null;
}
}
}
=======================================================================================
@Configuration
public class ShiroConfig {
//将自己的验证方式加入容器
@Bean
public UserRealm myShiroRealm() {
return new UserRealm();
}
/**
配置安全管理器 SecurityManager
@return
*/
@Bean
public DefaultWebSecurityManager securityManager() {
// 将自定义 Realm 加进来
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联 Realm
securityManager.setRealm(myShiroRealm());
return securityManager;
}
/**
配置 Shiro 过滤器
@param securityManager
@return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
// 定义 shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 关联 securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 自定义登录页面,如果登录的时候,就会执行这个请求,即跳转到登录页
shiroFilterFactoryBean.setLoginUrl("toLoginPage");
// 指定成功页面
shiroFilterFactoryBean.setSuccessUrl("/success");
// 指定未授权界面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 设置自定义 filter
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("anyRoleFilter", new MyRolesAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap);
// LinkedHashMap 是有序的,进行顺序拦截器配置
Map<String, String> filterChainMap = new LinkedHashMap<>();
// 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
filterChainMap.put("/css/**", "anon");
filterChainMap.put("/img/**", "anon");
filterChainMap.put("/js/**", "anon");
// 指定页面放行,例如登录页面允许所有人登录
filterChainMap.put("/toLoginPage", "anon");
// 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证
filterChainMap.put("/user/admin/**", "authc");
// 页面 -用户需要角色认证
filterChainMap.put("/levelA/**", "anyRoleFilter[USER,ADMIN,SUPER_ADMIN]");
filterChainMap.put("/levelB/**", "anyRoleFilter[ADMIN,SUPER_ADMIN]");
filterChainMap.put("/levelC/**", "anyRoleFilter[SUPER_ADMIN]");
// filterChainMap.put("/levelA/**", "roles[USER]");
// filterChainMap.put("/levelB/**", "roles[ADMIN]");
// filterChainMap.put("/levelC/**", "roles[SUPER_ADMIN]");
// /user/admin/ 下的所有请求都要经过权限认证,只有权限为 user:[*] 的可以访问,也可以具体设置到 user:xxx
filterChainMap.put("/user/admin/**", "perms[user:*]");
// 配置注销过滤器
filterChainMap.put("/logout", "logout");
// 将 Map 存入过滤器
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
return shiroFilterFactoryBean;
}
/**
整合 thymeleaf
@return
*/
评论