Shiro是我们常用的一个权限管理框架,我们之前已经详细的给大家介绍过了Shiro的基础知识,不太清楚的可以参考下 https://blog.csdn.net/qq_38526573/category_9284714.html 此文,本文的重点是来介绍下在SpringBoot环境下我们怎么来使用Shiro。
一、添加相关依赖
本案例中我们使用SpringDataJPA和Thymeleaf来配合讲解,所以相关的依赖如下
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </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> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <!-- springBoot的启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
二、添加相关的配置信息
在application.properties中添加如下的配置信息
# jdbc 的相关信息 spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/srm?characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=123456 # 配置连接池信息 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # 配置jpa的相关参数 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
三、业务准备
我们提前将登录认证的后台业务先完成。我们提前将登录认证的后台业务先完成。
1.对应的表结构
CREATE TABLE `t_user` ( `id` int(20) NOT NULL AUTO_INCREMENT, `username` varchar(20) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, `salt` varchar(100) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `state` int(1) DEFAULT NULL, `last_login_time` datetime DEFAULT NULL, `nickname` varchar(30) DEFAULT NULL, `realname` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
2.pojo对象
package com.dpb.springboot41shiro.pojo; import javax.persistence.*; /** * @program: springboot-41-shiro * @description: * @author: 波波烤鸭 * @create: 2019-11-29 20:06 */ @Entity @Table(name = "t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Column(name = "salt") private String salt; @Column(name = "realname") private String realname; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getSalt() { return salt; } public void setSalt(String salt) { this.salt = salt; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } }
3.dao接口
接口我们通过 JpaRepository接口来实现,然后根据名称规则来定义方法
public interface UserDao extends JpaRepository<User,Integer> { /** * 根据账号查询 * @param username * @return */ List<User> findByUsername(String username); }
4.业务层代码
业务层就实现简单的调用即可
四、Shiro整合
接下来我们就可以来整合Shiro框架了
1.自定义Realm文件
首先我们定义一个realm实现类来实现我们认证和授权的逻辑
package com.dpb.springboot41shiro.realm; import com.dpb.springboot41shiro.pojo.User; import com.dpb.springboot41shiro.service.UserService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.SimpleByteSource; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; /** * @program: springboot-41-shiro * @description: 自定义Realm * @author: 波波烤鸭 * @create: 2019-11-29 19:37 */ public class AuthcRealm extends AuthorizingRealm { /** * 认证的方法 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { return null; } /** * 授权的方法 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } }
逻辑可以稍后实现
2.Shiro的配置类
我们先来看下之前在spring整合shiro的时候,我们的整合配置文件:
那么我们在SpringBoot中只需将此配置转换为对应的java配置即可,如下
package com.dpb.springboot41shiro.config; import com.dpb.springboot41shiro.realm.AuthcRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @program: springboot-41-shiro * @description: Shiro的配置类 * @author: 波波烤鸭 * @create: 2019-11-29 19:31 */ @Configuration public class ShiroConfig { @Value("${shiro.hashAlgorithmName}") private String hashAlgorithmName; @Value("${shiro.hashIterations}") private Integer hashIterations; /** * 获取凭证匹配器 * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName(hashAlgorithmName); matcher.setHashIterations(hashIterations); return matcher; } /** * 获取自定义的Realm * @return */ @Bean public AuthcRealm authcRealm(){ AuthcRealm realm = new AuthcRealm(); realm.setCredentialsMatcher(hashedCredentialsMatcher()); return realm; } /** * 获取SecurityManager对象 * @return */ @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(authcRealm()); return manager; } /** * 注册ShiroFilterFactoryBean * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){ ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean(); filter.setSecurityManager(manager); filter.setLoginUrl("/login.do"); filter.setSuccessUrl("/success.html"); filter.setUnauthorizedUrl("/refuse.html"); // 设置过滤器 Map<String,String> map = new HashMap<>(); map.put("/css/**","anon"); map.put("/img/**","anon"); map.put("/js/**","anon"); map.put("/login","anon"); map.put("/login.do","authc"); map.put("/**","authc"); filter.setFilterChainDefinitionMap(map); return filter; } }
3.访问测试
到此shiro已经被集成到了我们项目中,我们可以根据我们配置的过滤链路来启动访问下,首先创建如下的相关文件,便于测试
同时添加对应的跳转控制器
/** * @program: springboot-41-shiro * @description: 基础控制器 * @author: 波波烤鸭 * @create: 2019-11-29 19:52 */ @Controller public class BaseController { @RequestMapping("/{path}") public String page(@PathVariable String path){ return path; } }
访问需要认证的success.html ,会给错误提示
访问img/a2.jpg可以直接访问
五、登录认证测试
接下来我们实现下认证的过程。
1.自定义realm实现登录
自定义realm认证的流程如下
@Autowired private UserService service; /** * 认证的方法 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String userName = token.getUsername(); System.out.println("开始登录认证:"+userName); List<User> list = service.login(userName); if (list == null || list.size() != 1) { return null; } User user = list.get(0); return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getSalt()),"authcRealme"); }
2.创建登录表单
前端我们用Thymeleaf来作为模块框架,创建登录表单
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登录管理</h1> <form th:action="@{/login.do}" method="post"> 账号:<input type="text" name="username"><br> 密码:<input type="text" name="password"><br> <input type="submit" value="登录"> </form> </body> </html>
3.创建认证的控制器
同时我们创建认证的控制器,来处理认证失败的情况
package com.dpb.springboot41shiro.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; /** * @program: springboot-41-shiro * @description: 认证的控制器 * @author: 波波烤鸭 * @create: 2019-11-29 20:12 */ @Controller public class AuthcController { @RequestMapping("/login.do") public String login(HttpServletRequest request){ Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME); System.out.println("认证的错误信息:" + obj); return "/login"; } /** * 注销的方法 * @return */ @RequestMapping("/logout.do") public String logout(){ SecurityUtils.getSubject().logout(); return "redirect:/login"; } }
4.准备数据
我们可以自己通过Md5加密一个密码然后保存到数据库中
5.测试
到此启动项目,登录测试即可
最后项目的目录结构如下: