springboot整合shiro
Posted 求知若渴的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot整合shiro相关的知识,希望对你有一定的参考价值。
一.数据库这块的准备需要创建五张表
数据库有用户(user)、角色(role)、权限(permission)三个实体,除了实体表以外,为了实现表间用户与角色、角色与权限多对多的表间关系,所以产生了user_role、role_permission两张关系表。在下图中,使用红线将表的外键标记了出来,但为了方便并没有在表中创建外键,我们手动进行维护
再简单介绍下数据库字段,user表中name是用户名,password是密码;role表中name是角色名(如user、vip);permission表中,name是权限名(如会员中心),url是实际的权限字段(user:vip)
对应的sql脚本
/*
SQLyog Professional v12.08 (64 bit)
mysql - 5.0.96-community-nt : Database - lastpass
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=‘‘*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=‘NO_AUTO_VALUE_ON_ZERO‘ */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`lastpass` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `lastpass`;
/*Table structure for table `permission` */
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` varchar(255) NOT NULL,
`name` varchar(100) default NULL,
`url` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `permission` */
insert into `permission`(`id`,`name`,`url`) values (‘1‘,‘用户中心‘,‘user:add‘),(‘2‘,‘会员中心‘,‘user:vip‘);
/*Table structure for table `role` */
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` varchar(50) NOT NULL,
`name` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `role` */
insert into `role`(`id`,`name`) values (‘1‘,‘user‘),(‘2‘,‘vip‘);
/*Table structure for table `role_permission` */
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`id` varchar(255) NOT NULL,
`role_id` varchar(255) NOT NULL,
`permission_id` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `role_permission` */
insert into `role_permission`(`id`,`role_id`,`permission_id`) values (‘1‘,‘1‘,‘1‘),(‘2‘,‘2‘,‘2‘);
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(255) NOT NULL,
`name` varchar(255) default NULL,
`password` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `user` */
insert into `user`(`id`,`name`,`password`) values (‘1‘,‘rhine‘,‘28e5ea71eb6600afb02132dcf27b8e75‘),(‘2‘,‘vip‘,‘01ffb6fc48048d105ba5061f8df5a35e‘);
/*Table structure for table `user_role` */
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` varchar(255) NOT NULL,
`user_id` varchar(255) NOT NULL,
`role_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `user_role` */
insert into `user_role`(`id`,`user_id`,`role_id`) values (‘1‘,‘1‘,‘1‘),(‘2‘,‘2‘,‘1‘),(‘3‘,‘2‘,‘2‘);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
二.创建springboot项目
1.添加shiro的依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.创建实体
package com.rhine.blog.po;
import java.io.Serializable;
/**
* @description 权限类
*/
public class PermissionBean implements Serializable {
private String id;
private String name;
private String url;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
package com.rhine.blog.po;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* @description 角色类
*/
public class RoleBean implements Serializable {
private String id;
private String name;
private Set<PermissionBean> permissions = new HashSet<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<PermissionBean> getPermissions() {
return permissions;
}
public void setPermissions(Set<PermissionBean> permissions) {
this.permissions = permissions;
}
}
package com.rhine.blog.po;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* @description 用户类
*/
public class UserBean implements Serializable {
private String id;
private String name;
private String password;
private Set<RoleBean> roles = new HashSet<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<RoleBean> getRole() {
return roles;
}
public void setRole(Set<RoleBean> roles) {
this.roles = roles;
}
}
3.创建shiro的配置类userRealm和shiroConfig
import com.rhine.blog.po.PermissionBean;
import com.rhine.blog.po.RoleBean;
import com.rhine.blog.po.UserBean;
import com.rhine.blog.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
**/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Subject subject = SecurityUtils.getSubject();
UserBean user = (UserBean)subject.getPrincipal();
if(user != null){
//用户已经完成登录 给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 角色与权限字符串集合
Collection<String> rolesCollection = new HashSet<>();
Collection<String> premissionCollection = new HashSet<>();
Set<RoleBean> roles = user.getRole();
for(RoleBean role : roles){
rolesCollection.add(role.getName());
Set<PermissionBean> permissions = role.getPermissions();
for (PermissionBean permission : permissions){
premissionCollection.add(permission.getUrl());
}
//添加资源的授权字符串
//这块的需要与shiro类中filterMap.put("/vip/index", "perms[user:vip]")
//的保持一致才能起到授权的效果;
info.addStringPermissions(premissionCollection);
}
info.addRoles(rolesCollection);
return info;
}
return null;
}
/**
* 认证
**/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取用户的名字
String userName =(String)authenticationToken.getPrincipal();
//通过用户名获得user对象
UserBean bean = userService.findByName(userName);
if(bean == null){
throw new UnknownAccountException();
}
ByteSource byteSource = ByteSource.Util.bytes(bean.getName());
// 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(bean, bean.getPassword(),byteSource, bean.getName());
return authenticationInfo;
}
}
package com.rhine.blog.config;
import com.rhine.blog.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author chenyuyu
* @description Shiro配置类
* @date Created in 16:07 2018/12/6
* @modified By:
*/
@Configuration
public class ShiroConfig {
@Bean("hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//指定加密方式为MD5
credentialsMatcher.setHashAlgorithmName("MD5");
//加密次数
credentialsMatcher.setHashIterations(1024);
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
@Bean("userRealm")
public UserRealm userRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(matcher);
return userRealm;
}
@Bean
public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置 SecurityManager
bean.setSecurityManager(securityManager);
bean.setSuccessUrl("/main");
// 设置登录跳转页面
bean.setLoginUrl("/toLogin");
// 设置未授权提示页面
bean.setUnauthorizedUrl("/error/unAuth");
/**
* Shiro内置过滤器,可以实现拦截器相关的拦截器
* 常用的过滤器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*
* //授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/update", "perms[user:update]");
*
*
**/
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/login","anon");
filterMap.put("/user/index","authc");
//filterMap.put("/vip/index","roles[vip]");
//filterMap.put("/vip/index","roles[user]");
filterMap.put("/druid/**", "anon");
filterMap.put("/static/**","anon");
//filterMap.put("/vip/index", "perms[user:vip]");
filterMap.put("/**","authc");
filterMap.put("/logout", "logout");
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
/**
* 注入 securityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(HashedCredentialsMatcher hashedCredentialsMatcher) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联realm.
securityManager.setRealm(userRealm(hashedCredentialsMatcher));
return securityManager;
}
}
认证对应的controller
package com.rhine.blog.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class MainController {
/**
* 登录后进入首页
* @param request
* @param response
* @return
*/
@RequestMapping("/main")
public String index(HttpServletRequest request, HttpServletResponse response){
response.setHeader("root", request.getContextPath());
return "index";
}
/**
* 进入登陆页面
* @param request
* @param response
* @return
*/
@RequestMapping("/toLogin")
public String toLogin(HttpServletRequest request, HttpServletResponse response){
response.setHeader("root", request.getContextPath());
return "login";
}
/**
* 登录访问的页面
* @param request
* @param response
* @return
*/
@RequestMapping("/login")
public String login(HttpServletRequest request, HttpServletResponse response){
response.setHeader("root", request.getContextPath());
String userName = request.getParameter("username");
String password = request.getParameter("password");
if(!StringUtils.isEmpty(userName)){
// 1.获取Subject
Subject subject = SecurityUtils.getSubject();
// 2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
// 3.执行登录方法
try{
subject.login(token); //访问UserRealm中doGetAuthenticationInfo方法
return "redirect:/main";
} catch (UnknownAccountException e){
System.out.println("用户名不存在!");
request.setAttribute("msg","用户名不存在!");
} catch (IncorrectCredentialsException e){
System.out.println("密码错误!");
request.setAttribute("msg","密码错误!");
}
}
return "login";
}
/**
* 推出登录
* @return
*/
@RequestMapping("/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
subject.logout();
}
return "redirect:/main";
}
@RequestMapping("/error/unAuth")
public String unAuth(){
return "/error/unAuth";
}
}
权限控制对应的controller
package com.rhine.blog.controller;
import com.rhine.blog.po.UserBean;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class UserController {
@RequestMapping("/user/index")
public String add(HttpServletRequest request){
UserBean bean = (UserBean) SecurityUtils.getSubject().getPrincipal();
request.setAttribute("userName", bean.getName());
return "/user/index";
}
@RequestMapping("/vip/index")
public String update(){
return "/vip/index";
}
}
以上是关于springboot整合shiro的主要内容,如果未能解决你的问题,请参考以下文章