**springboot浅整合shiro**
一.简单需求
java后端实现简单权限,角色的控制
二.核心
springboot,shiro,mybtis-plus,mysql
三.数据库设计思路
设计对应的用户表,角色表,权限表,用户角色表,角色权限表,来实现对用户分配角色,对角色分配权限等操作.
用户表(user)
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`account` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '账号',
`pwd` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码',
`rid` bigint unsigned DEFAULT '4' COMMENT '角色编号',
`status` int DEFAULT '1' COMMENT '状态',
`info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '名称信息',
`phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '电话',
`photo` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '头像',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
角色表(role)
CREATE TABLE `role` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色编号',
`role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色名称',
`info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色信息',
`status` bigint DEFAULT '1' COMMENT '状态',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
权限表(permission)
CREATE TABLE `permission` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '权限编号',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '权限名称',
`info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '权限标识',
`status` bigint DEFAULT '1' COMMENT '状态',
`create_date` timestamp NULL DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
用户角色(user_role)
CREATE TABLE `user_role` (
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户角色编号',
`user_id` bigint DEFAULT NULL COMMENT '用户ID',
`role_id` bigint DEFAULT NULL COMMENT '角色ID',
`status` bigint DEFAULT '1' COMMENT '状态',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
角色权限(role_permission)
CREATE TABLE `role_permission` (
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色权限编号',
`role_id` bigint DEFAULT NULL COMMENT '角色ID',
`permission_id` bigint DEFAULT NULL COMMENT '权限ID',
`status` bigint DEFAULT '1' COMMENT '状态',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC
四.项目搭建及整合
1.创建springboot项目具体流程很简单,展示整合
pom文件
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
yaml文件:
server:
port: 8085
servlet:
session:
timeout: 24h
spring:
datasource:
url: jdbc:mysql://localhost:3306/***?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: ***
password: ***
driver-class-name: com.mysql.cj.jdbc.Driver
main:
allow-bean-definition-overriding: true
resources:
static-locations: *******
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
mybatis-plus:
mapper-locations: classpath:mappers/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus配置控制台打印完整带参数SQL语句 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
2.开始对shiro整合
shiro认证登录概念:在shiro中通过用户的唯一属性(身份ID,手机号等)身份证明,交给shiro,从而验证
登录认证流程:
1.手机用户信息
2.调用subject.login()方法进行登录,失败则返回对应异常
3.创建自定义的Realm类,继承AuthorizingRealm类,实现认证登录方法doGetAuthenticationInfo()
角色授权概念:代表用户经过分配到角色对应的权限信息,才能访问资源,
角色授权流程及授权方式:通过Realm中doGetAuthorizationInfo()方法进行授权,我是通过接口服务注解来进行权限的鉴别.
3.Realm类
Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息,它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro 。当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和或授权。配置多个 Realm 是可以的,但是必须需要一个。综上所述,想要实现权限Realm文件十分的重要,话不多说上代码
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//认证授权接口方法:获取当前登录用户的角色,权限信息,返回给shiro进行授权认证
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("自定义授权方法");
//获取当前登录身份信息
String principal = principals.getPrimaryPrincipal().toString();
//调用数据库查看对应角色
List<String> userRole = userService.getUserRole(principal);
System.out.println("当前登录用户角色信息 = " + userRole);
//查看当前登录用户数据库权限
List<String> userPermission = userService.getUserPermission(userRole);
System.out.println("当前登录用户的权限信息= " + userPermission);
//1.创建对象,封装当前登录用户的角色,权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//存储角色
info.addRoles(userRole);
info.addStringPermissions(userPermission);
//返回
return info;
}
//认证登录接口
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取身份信息
String account = token.getPrincipal().toString();
//调用业务层获取数据库用户信息
User user = userService.getUserName(account);
//非空判断,进行数据返回
if(user !=null){
//这里采用shiro的加密带盐
AuthenticationInfo info= new SimpleAuthenticationInfo(token.getPrincipal(),
user.getPwd(),ByteSource.Util.bytes("salt"),token.getPrincipal().toString()
);
return info;
}
return null;
}
}
代码中认证登录,我的唯一属性,用户账户
@Override
public User getUserName(String account) {
//mybatisPlus 特有的参数构造器
QueryWrapper wrapper = new QueryWrapper<User>();
wrapper.eq("account",account);
User user = userMapper.selectOne(wrapper);
return user;
}
代码中授权sql
当前登录用户角色信息 <select id="getUserRole" resultType="java.lang.String"> SELECT role_name FROM role r WHERE r.
id IN( SELECT role_id FROM user_role ur WHERE ur.
user_id IN( SELECT id FROM USER u WHERE u.
account=#{account} ) ) </select>
当前登录用户权限信息
//认证权限
@Select({
"<script>",
"SELECT info FROM permission p WHERE p.`id`IN",
"(SELECT permission_id FROM role_permission rp WHERE rp.`role_id` IN(",
"SELECT id FROM role WHERE role_name IN" +
"<foreach collection='roleNames' item='roleName' open='(' separator=',' close=')'>",
"#{roleName}",
"</foreach>",
"))",
"</script>"
})
List<String> getUserPermission( @Param("roleNames") List<String> roleNames);
4.shiro配置类
可以在这里面对url的拦截以及在上述文章中的shiro加密带盐操作
//shiro 配置类
@Configuration
public class ShiroConfig {
@Resource
private MyRealm myRealm;
//配置SecurityMangaer
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
//创建一个DefaultWebSecurityManager对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//创建加密对象HashedCredentialsMatcher
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//设置加密的方式
matcher.setHashAlgorithmName("md5");//加密格式
matcher.setHashIterations(3);//加密次数
//将加密对象存储到MyRealm
myRealm.setCredentialsMatcher(matcher);
//将myRealm封装到webSecurityManager对象中
defaultWebSecurityManager.setRealm(myRealm);
//返回
return defaultWebSecurityManager;
}
//配置shiro内置过滤器拦截范围
@Bean
public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
//可根据业务需求实际配置
//创建DefaultShiroFilterChainDefinition 对象
DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
//设置不认证可以访问的资源
defaultShiroFilterChainDefinition.addPathDefinition("/rest/loginController/userLogin","anon");
//设置需要认证登录拦截的范围
defaultShiroFilterChainDefinition.addPathDefinition("/**","anon");
return defaultShiroFilterChainDefinition;
}
}插入代码片
5.创建自定义的异常处理类
可以抓取shiro登录,授权的异常处理信息,返回前端
@Slf4j
@RestController
@CrossOrigin
@RequestMapping("/rest/loginController")
public class LoginController {
@Autowired
private HttpServletRequest request;
@Autowired
private UserService userService;
@Autowired
private LoginService loginService;
//登录
@RequestMapping(value = "/userLogin",method = RequestMethod.POST)
public Result login(@RequestBody User user){
//获取Subject对象
Subject subject = SecurityUtils.getSubject();
//获取web数据封装到token
AuthenticationToken token = new UsernamePasswordToken(user.getAccount(),user.getPwd());
//调用login方法进行认证
try {
subject.login(token);
User userInfo = userService.getUserName(user.getAccount());
request.getSession().setAttribute(LONINUSER,userInfo);
System.out.println("userInfo = " + userInfo);
JSONObject object = new JSONObject();
object.put("user",userInfo);
object.put("token",StringUtil.getUUID());
return Result.success(object,"登陆成功");
}catch (UnknownAccountException e){
System.out.println("用户名不存在");
return Result.fail("用户名不存在");
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
return Result.fail("密码错误");
}catch (AuthenticationException e){
e.printStackTrace();
return Result.fail("登陆失败");
}
}
}
6.鉴别方式
在后端实现的接口上添加 @RequiresRoles(“admin”)鉴别角色注解,
@RequiresPermissions(“note:add”)鉴别权限注解,注解中的标识符自定义,然后存在对应的数据库,具体看上述数据库的展示图片.
总结
本文章只是浅谈及展示一下侧重于java后端的操作,一些具体的概念,流程不懂得可以自己去学习一下,若本文章不正之处,请谅解.