Shiro整合SpringBoot项目实战
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:SpringBoot 框架从入门到精通
✨特色专栏:国学周更-心性养成之路
🥭本文内容:Shiro整合SpringBoot项目实战
文章目录
-
-
- 6.0 整合思路
- 6.1 创建springboot项目
- 6.2 引入shiro依赖
- 6.3 配置shiro环境
-
-
- 0.创建配置类
- 1.配置shiroFilterFactoryBean
- 2.配置WebSecurityManager
- 3.创建和配置自定义realm
- 4.编写主页面index.jsp
- 5.启动项目,访问index.jsp
- 6.加入权限控制
- 7.重启项目访问查看
-
- 6.4 常见过滤器
- 6.5 认证实现
-
-
- 1. 在login.jsp中开发认证界面
- 2. 开发controller
- 3.开发realm中返回静态数据(未连接数据库)
- 4.启动项目以realm中定义静态数据进行认证
-
- 6.6 退出认证
-
-
- 1.开发页面退出连接
- 2.开发controller
- 3.修改退出连接访问退出路径
- 4.退出之后访问受限资源立即返回认证界面
-
- 6.7 MD5、Salt的认证实现
-
- 1.开发数据库注册
-
- 0.开发注册界面
- 1.创建数据表结构
- 2.项目引入依赖
- 3.配置application.properties配置文件
- 4.创建entity
- 5.创建DAO接口
- 6.开发mapper配置文件
- 7.开发service接口
- 8.创建salt工具类
- 9.开发service实现类
- 10.开发Controller
- 11.启动项目进行注册
- 2.开发数据库认证
-
- 0.开发DAO
- 1.开发mapper配置文件
- 2.开发Service接口
- 3.开发Service实现类
- 4.开发在工厂中获取bean对象的工具类
- 5.修改自定义realm
- 6.修改ShiroConfig中realm
-
6.0 整合思路
6.1 创建springboot项目
6.2 引入shiro依赖
在pom.xml文件中添加Shiro依赖。可以选择使用Shiro的starter,也可以手动添加Shiro的依赖。
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.5.3</version>
</dependency>
6.3 配置shiro环境
0.创建配置类
在Spring Boot应用程序中,可以通过编写一个Shiro配置类来配置Shiro。在该类中,可以定义Shiro的安全管理器
、Realm
、过滤器
等组件,并将它们注入Spring容器中。
1.配置shiroFilterFactoryBean
Shiro过滤器是实现基于角色或权限的访问控制的核心组件。可以通过编写一个ShiroFilter配置类来定义Shiro过滤器链,并将其注入到Spring容器中。
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){//创建shiro的filterShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//注入安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean;
}
2.配置WebSecurityManager
DefaultWebSecurityManager
类主要定义了设置subjectDao
,获取会话模式,设置会话模式,设置会话管理器,是否是http会话模式等操作,它继承了DefaultSecurityManager
类,实现了WebSecurityManager
接口
@Bean
public DefaultWebSecurityManager getSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;
}
3.创建和配置自定义realm
在Shiro中,Realm是连接应用程序和安全数据源的桥梁。通过实现自定义的Realm,可以将Shiro连接到应用程序的数据库、LDAP目录或其他数据源中。在自定义Realm中,需要实现认证
和授权
逻辑,并将其注入到Shiro的安全管理器中。
public class CustomerRealm extends AuthorizingRealm {//处理授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//处理认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return null;}
}
//创建自定义realm
@Bean
public Realm getRealm(){return new CustomerRealm();
}
4.编写主页面index.jsp
5.启动项目,访问index.jsp
默认在配置好shiro环境后默认环境中没有对项目中任何资源进行权限控制,所有现在项目中所有资源都可以通过路径访问
6.加入权限控制
修改ShiroFilterFactoryBean配置
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//配置系统的受限资源 authc//配置系统的公共资源 anonHashMap<String, String> map = new HashMap<>();map.put("/index.jsp", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(map);shiroFilterFactoryBean.setLoginUrl("/login.jsp");return shiroFilterFactoryBean;}
/** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表
7.重启项目访问查看
6.4 常见过滤器
- 注意: shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限:
配置缩写 | 对应的过滤器 | 功能 |
---|---|---|
anon | AnonymousFilter | 指定url可以匿名访问 |
authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取username 、password ,rememberMe 等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 |
authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 |
logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 |
noSessionCreation | NoSessionCreationFilter | 禁止创建会话 |
perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 |
port | PortFilter | 需要指定端口才能访问 |
rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 |
roles | RolesAuthorizationFilter | 需要指定角色才能访问 |
ssl | SslFilter | 需要https请求才能访问 |
user | UserFilter | 需要已登录 或“记住我” 的用户才能访问 |
6.5 认证实现
1. 在login.jsp中开发认证界面
<form action="${pageContext.request.contextPath}/user/login" method="post">用户名:<input type="text" name="username" > <br/>密码 : <input type="text" name="password"> <br><input type="submit" value="登录">
</form>
2. 开发controller
@Controller
@RequestMapping("user")
public class UserController {/*** 用来处理身份认证* @param username* @param password* @return*/@RequestMapping("login")public String login(String username,String password){//获取主体对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return "redirect:/index.jsp";} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!");}return "redirect:/login.jsp";}
}
- 在认证过程中使用subject.login进行认证
3.开发realm中返回静态数据(未连接数据库)
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");String principal = (String) token.getPrincipal();if("mosin".equals(principal)){return new SimpleAuthenticationInfo(principal,"123",this.getName());}return null;}
}
4.启动项目以realm中定义静态数据进行认证
- 认证功能没有md5和随机盐的认证就实现啦
6.6 退出认证
1.开发页面退出连接
2.开发controller
@Controller
@RequestMapping("user")
public class UserController {/*** 退出登录**/@RequestMapping("logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();//退出用户return "redirect:/login.jsp";}
}
3.修改退出连接访问退出路径
4.退出之后访问受限资源立即返回认证界面
6.7 MD5、Salt的认证实现
1.开发数据库注册
0.开发注册界面
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">用户名:<input type="text" name="username" > <br/>密码 : <input type="text" name="password"> <br><input type="submit" value="立即注册">
</form>
1.创建数据表结构
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (`id` int(6) NOT NULL AUTO_INCREMENT,`username` varchar(40) DEFAULT NULL,`password` varchar(40) DEFAULT NULL,`salt` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;SET FOREIGN_KEY_CHECKS = 1;
2.项目引入依赖
<!--mybatis相关依赖-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version>
</dependency><!--mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><!--druid-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.19</version>
</dependency>
3.配置application.properties配置文件
server.port=8888
server.servlet.context-path=/shiro
spring.application.name=shirospring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
#新增配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=rootmybatis.type-aliases-package=cn.kgc.springboot_jsp_shiro.entity
mybatis.mapper-locations=classpath:mapper/*.xml
4.创建entity
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {private String id;private String username;private String password;private String salt;
}
5.创建DAO接口
@Mapper
public interface UserDAO {void save(User user);
}
6.开发mapper配置文件
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">insert into t_user values(#{id},#{username},#{password},#{salt})
</insert>
7.开发service接口
public interface UserService {//注册用户方法void register(User user);
}
8.创建salt工具类
public class SaltUtils {/*** 生成salt的静态方法* @param n* @return*/public static String getSalt(int n){char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();StringBuilder sb = new StringBuilder();for (int i = 0; i < n; i++) {char aChar = chars[new Random().nextInt(chars.length)];sb.append(aChar);}return sb.toString();}
}
9.开发service实现类
@Service
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDAO userDAO;@Overridepublic void register(User user) {//处理业务调用dao//1.生成随机盐String salt = SaltUtils.getSalt(8);//2.将随机盐保存到数据user.setSalt(salt);//3.明文密码进行md5 + salt + hash散列Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());userDAO.save(user);}
}
10.开发Controller
@Controller
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册*/@RequestMapping("register")public String register(User user) {try {userService.register(user);return "redirect:/login.jsp";}catch (Exception e){e.printStackTrace();return "redirect:/register.jsp";}}
}
11.启动项目进行注册
2.开发数据库认证
0.开发DAO
@Mapper
public interface UserDAO {void save(User user);//根据身份信息认证的方法User findByUserName(String username);
}
1.开发mapper配置文件
<select id="findByUserName" parameterType="String" resultType="User">select id,username,password,salt from t_userwhere username = #{username}
</select>
2.开发Service接口
public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username);
}
3.开发Service实现类
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDAO userDAO;@Overridepublic User findByUserName(String username) {return userDAO.findByUserName(username);}
}
4.开发在工厂中获取bean对象的工具类
@Component
public class ApplicationContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;}//根据bean名字获取工厂中指定bean 对象public static Object getBean(String beanName){return context.getBean(beanName);}
}
5.修改自定义realm
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");//根据身份信息String principal = (String) token.getPrincipal();//在工厂中获取service对象UserService userService = (UserService) ApplicationContextUtils.getBean("userService");//根据身份信息查询User user = userService.findByUserName(principal);if(!ObjectUtils.isEmpty(user)){//返回数据库信息return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;}
6.修改ShiroConfig中realm
使用凭证匹配器以及hash散列
@Bean
public Realm getRealm(){CustomerRealm customerRealm = new CustomerRealm();//设置hashed凭证匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置md5加密credentialsMatcher.setHashAlgorithmName("md5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm;
}
码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识,点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。