1新建spring项目
导入依赖:`<?xml version="1.0" encoding="UTF-8"?>
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.2.RELEASE
com.myshrio
demo
0.0.1-SNAPSHOT
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.目录结构
3.shiro的配置
1.自定义realm
package com.myshrio.shiro;
import com.myshrio.pojo.Permission;
import com.myshrio.pojo.Role;
import com.myshrio.pojo.User;
import com.myshrio.services.IUserSer;
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.springframework.beans.factory.annotation.Autowired;
import java.security.Permissions;
public class CustomRealm extends AuthorizingRealm {
@Autowired
private IUserSer iUserSer;//用了ioc不用new
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
//根据用户名去数据库查询用户信息
User user = iUserSer.getByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRname());
}
//添加权限
for (Permission permissions :user.getPermissions()) {
simpleAuthorizationInfo.addStringPermission(permissions.getPname());
}
return simpleAuthorizationInfo;
}
//用户身份验证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();//用户名
User user =iUserSer.getByName(name);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getUpass(), getName());
return simpleAuthenticationInfo;
}
}
}
主要包含用户验证和,权限注入。
2.shiro的配置,我们使用Java代码配置
package com.myshrio.config;
import com.myshrio.shiro.CustomRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
//将自己的验证方式加入容器
@Bean
public CustomRealm myShiroRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
//登出
map.put("/logout", "logout");
//对所有用户认证
map.put("/**", "authc");
map.put("layui/** ","anon");
map.put("/login.html","anon");//anon直接访问
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
其中关于过滤器配值大加可以参考过滤器配置参数
4.Mybatis
1.实体类
(权限类)
package com.myshrio.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Permission implements Serializable {
private int id;
private String pname;
private String description;
}
(用户类)
package com.myshrio.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private int id;
private String uname;
private String upass;
private List<String> user_r;//用户所有角色
private List<String> role_p;//用户所有权限
private List<Role> roles;
private List<Permission> permissions;
}
(角色类)
package com.myshrio.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role implements Serializable {
private int id;
private String rname;
private String description;
}
2.Dao
package com.myshrio.dao;
import com.myshrio.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IuserDao {
User queById (int uid);
User queByName(String name);
}
说明:本次只写了userDao,之前将permission和role写入user实体类中了(5表联合查询)。
(Mapper.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">
<!--
mybatis的第二种事件方式
xml + 接口的方式
特点:xml中的namespace必须为接口的全路径
xml中的每个节点的id必须为接口的方法名
-->
<mapper namespace="com.myshrio.dao.IuserDao">
<select id="queById" resultMap="userMap">
select * from userinfo where id=#{uid}
</select>
<resultMap id="userMap" type="com.myshrio.pojo.User">
<id column="id" property="id" />
<collection property="user_r" column="id" select="getrname" />
<collection property="role_p" column="id" select="getpname" />
</resultMap>
<select id="getrname" resultType="String">
SELECT r.rname
FROM userinfo u INNER JOIN user_r ur ON u.id = ur.uid
INNER JOIN role r ON r.id=ur.rid
INNER JOIN role_p rp ON ur.rid=rp.rid
WHERE u.id=#{uid} GROUP BY ur.rid/*单个用户的所有角色*/
</select>
<select id="getpname" resultType="String">
SELECT p.pname,p.description FROM userinfo u
INNER JOIN user_r ur ON u.id = ur.uid
INNER JOIN role r ON r.id=ur.rid
INNER JOIN role_p rp ON ur.rid=rp.rid
INNER JOIN permission p ON rp.pid=p.id
WHERE u.id=#{uid} GROUP BY rp.pid/*单个用户的所有权限*/
</select>
<!-- ====================================================================================== -->
<select id="queByName" resultMap="userMap1">
select * from userinfo where uname =#{uname}
</select>
<resultMap id="userMap1" type="com.myshrio.pojo.User">
<id column="id" property="id" />
<result column="uname" property="uname" />
<collection property="roles" column="uname" select="getRole" />
<collection property="permissions" column="uname" select="getPermission" />
</resultMap>
<select id="getRole" resultType="com.myshrio.pojo.Role">
SELECT r.rname,r.description
FROM userinfo u INNER JOIN user_r ur ON u.id = ur.uid
INNER JOIN role r ON r.id=ur.rid
INNER JOIN role_p rp ON ur.rid=rp.rid
WHERE u.uname =#{uname} GROUP BY ur.rid/*单个用户的所有角色*/
</select>
<select id="getPermission" resultType="com.myshrio.pojo.Permission">
SELECT p.pname,p.description FROM userinfo u
INNER JOIN user_r ur ON u.id = ur.uid
INNER JOIN role r ON r.id=ur.rid
INNER JOIN role_p rp ON ur.rid=rp.rid
INNER JOIN permission p ON rp.pid=p.id
WHERE u.uname =#{uname} GROUP BY rp.pid/*单个用户的所有权限*/
</select>
</mapper>
5.controller
package com.myshrio.controller;
import com.myshrio.Util.Md5;
import com.myshrio.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
public class LoginController {
@RequestMapping("/login")
public String login(User user, HttpServletResponse response) throws IOException {
if (user.getUpass()==null||user.getUname()==null){
response.sendRedirect("login.html");//没有输入就到登录界面
}
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
user.getUname(),//输入的用户名
Md5.getPass(user.getUpass())//获得加密后的密码
);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
// subject.checkRole("admin");
// subject.checkPermissions("query", "add");
} catch (AuthenticationException e) {
e.printStackTrace();
return "账号或密码错误!";
} catch (AuthorizationException e) {
e.printStackTrace();
return "没有权限";
}
return "login success";
}
//注解验角色和权限
@RequiresRoles("admin")
@RequiresPermissions("delete")
@RequestMapping("/delete")
public String delete() {
return "删除权限!";
}
}
(这里只演示delete方法的访问,只有拥有delete权限才可以访问)
6.演示
(访问delete)
(换一个普通用户试试)