目录
1.springboot整合shiro-----认证(登录)
1.springboot整合shiro-----认证(登录)
1.1.创建springboot项目

1.2.引依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--shiro和springboot整合的依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
1.3.修改application配置文件
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql:///shiro?serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456789 #日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus.mapper-locations=classpath:/mapper/*.xml #thymeleaf的视图解析器 spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html #定义shiro的加密算法 shiro.hashAlgorithmName=MD5 shiro.hashIterations=1024
1.4.创建实体类
@Data public class Permission { @TableId(type = IdType.AUTO) private Integer perid; private String pername; private String percode; }@Data public class User implements Serializable { @TableId(type = IdType.AUTO) private Integer userid; private String username; private String userpwd; private String sex; private String address; private String salt; }
1.5.创建dao层
public interface UserDao extends BaseMapper<User> { }
开启扫描dao包
1.6.创建service层
public interface UserService { public User findByUsername(String username); }@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public User findByUsername(String username) { // 创建一个查询条件包装器 QueryWrapper<User> wrapper = new QueryWrapper<>(); // 设置查询条件为"username = username" wrapper.eq("username", username); // 使用查询条件执行查询操作,返回单个用户对象 User user = userDao.selectOne(wrapper); return user; } }
1.7.编写realm
public class MyRealm extends AuthorizingRealm { @Autowired protected UserService userService; // 授权--权限 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 在此处添加授权逻辑 return null; } //认证 -- 登录 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 1. 获取登录账号 String username = token.getPrincipal().toString(); // 2. 根据账号获取用户信息 User user = userService.findByUsername(username); if (user != null) { // 使用用户的盐值创建 ByteSource 对象 ByteSource salt = ByteSource.Util.bytes(user.getSalt()); // 创建 SimpleAuthenticationInfo 对象,包含用户信息、密码、盐值和 Realm 名称 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName()); return info; } // 用户不存在,返回 null return null; } }
1.8.创建vo层
@Data public class LoginVo { private String Password; private String Username; }
1.9.创建Controller层
@Controller public class LoginController { @PostMapping("/login") public String login(LoginVo loginVo) { // 获取当前主体对象 Subject subject = SecurityUtils.getSubject(); // 创建用户名密码令牌 UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUsername(), loginVo.getPassword()); try { // 调用主体的登录方法进行认证 subject.login(token); // 登录成功,返回成功标识 return "success"; } catch (Exception e) { e.printStackTrace(); // 登录失败,重定向到登录页面 return "redirect:/login.html"; } } }
1.10. 创建shiro的配置类
----(相当于ssm中的spring配置文件)
package com.wqg.config; import com.wqg.realm.MyRealm; 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.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.Filter; import java.util.HashMap; import java.util.Map; /** * @ fileName:ShiroConfig * @ description: * @ author:wqg * @ createTime:2023/7/7 16:33 */ @Configuration public class ShiroConfig { @Bean public DefaultWebSecurityManager securityManager() { // 创建默认的 Web 安全管理器 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置安全管理器使用的 Realm securityManager.setRealm(myRealm()); // 返回安全管理器 return securityManager; } @Bean public MyRealm myRealm(){ MyRealm myRealm=new MyRealm(); //设置密码加密器 myRealm.setCredentialsMatcher(credentialsMatcher()); return myRealm; } @Value("${shiro.hashAlgorithmName}") private String hashAlgorithmName; @Value("${shiro.hashIterations}") private int hashIterations; @Bean public HashedCredentialsMatcher credentialsMatcher() { // 创建密码匹配器对象 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); // 设置密码算法名称 credentialsMatcher.setHashAlgorithmName(hashAlgorithmName); // 设置哈希迭代次数 credentialsMatcher.setHashIterations(hashIterations); // 返回密码匹配器对象 return credentialsMatcher; } @Bean(name = "shiroFilter") public ShiroFilterFactoryBean factoryBean() { // 创建 Shiro 过滤器工厂 Bean ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager()); // 设置登录页面的 URL shiroFilterFactoryBean.setLoginUrl("/login.html"); // 设置过滤规则 Map<String, String> map = new HashMap<>(); // 指定 /login URL 不需要进行认证 map.put("/login", "anon"); // 其他 URL 需要进行认证 map.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); // 返回 Shiro 过滤器工厂 Bean return shiroFilterFactoryBean; } //springboot如何注册web三大组件。 @Bean public FilterRegistrationBean<Filter> filterRegistrationBean() { // 创建过滤器注册Bean对象 FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(); // 设置过滤器为DelegatingFilterProxy filterRegistrationBean.setFilter(new DelegatingFilterProxy()); // 设置过滤器名称 filterRegistrationBean.setName("shiroFilter"); // 添加过滤器的URL模式,匹配所有URL filterRegistrationBean.addUrlPatterns("/*"); // 返回过滤器注册Bean对象 return filterRegistrationBean; } }
1.11.创建登录页面与登录成功页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <form action="/login" method="post"> 姓名:<input type="text" name="username" /><br><br> 密码:<input type="text" name="password"/><br><br> <input type="submit" value="登录"/> </form> </body> </html><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 登录成功~~~ </body> </html>
1.12.测试
2.springboot整合shiro--授权(权限)
2.1.修改Realm
@Autowired protected PermissionService permissionService; // 授权--权限 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取主体中的用户对象 User user = (User) principals.getPrimaryPrincipal(); // 根据用户ID查询用户权限列表 List<String> list = permissionService.selectPermissionByUserid(user.getUserid()); // 如果权限列表不为空 if (list.size() != 0) { // 创建 SimpleAuthorizationInfo 对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 将权限列表添加到授权信息中 info.addStringPermissions(list); // 返回授权信息 return info; } // 返回空,表示无授权信息 return null; }2.2.创建Service
public interface PermissionService { public List<String> selectPermissionByUserid(Integer userid); }@Service public class PermissionServiceImpl implements PermissionService { @Autowired private PermissionDao permissionDao; @Override public List<String> selectPermissionByUserid(Integer userid) { // 根据用户ID查询用户权限列表 List<Permission> permissionList = permissionDao.findPermissionByUserid(userid); // 使用流操作将权限列表中的每个权限对象映射为权限编码,并收集为新的列表 List<String> collect = permissionList.stream().map(Permission::getPercode).collect(Collectors.toList()); // 返回权限编码列表 return collect; } }2.3.创建PermissionDao
@Mapper public interface PermissionDao extends BaseMapper<Permission> { List<Permission> findPermissionByUserid(Integer userid); }2.4.创建PermissionDao.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" > <mapper namespace="com.wqg.dao.PermissionDao"> <select id="findPermissionByUserid" resultType="com.wqg.entity.Permission"> select p.* from user_role ur join role_permission rp on ur.roleId=rp.roleid join permission p on rp.perid=p.perid where ur.userid=#{userId} </select> </mapper>2.5.创建UserController
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/query") @RequiresPermissions(value = {"user:query","user:delete"},logical = Logical.OR) //可以通过多个路径访问内部资源 //@RequiresPermissions(value = "user:query") public String query(){ return "user:query------------------------"; } @GetMapping("/update") @RequiresPermissions(value = "user:update") public String update(){ return "user:update------------------------"; } @GetMapping("/delete") @RequiresPermissions(value = "user:delete") public String delete(){ return "user:delete------------------------"; } @GetMapping("/insert") @RequiresPermissions(value = "user:insert") public String insert(){ return "user:insert------------------------"; } @GetMapping("/export") @RequiresPermissions(value = "user:export") //该注解不能被识别 public String export(){ return "user:export------------------------"; } }2.6.修改登录成功页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 登录成功~~~ <h1 shiro:hasPermission="user:insert"> <a href="/user/insert">增</a> </h1> <h1 shiro:hasPermission="user:delete"> <a href="/user/delete">删</a> </h1> <h1 shiro:hasPermission="user:update"> <a href="/user/update">改</a> </h1> <h1 shiro:hasPermission="user:query"> <a href="/user/query">查</a> </h1> </body> </html>2.7.添加依赖
<!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>2.8.ShiroConfig修改
/** * 这里是为了能在html页面引用shiro标签, */ @Bean(name = "shiroDialect") public ShiroDialect shiroDialect() { // 创建 Shiro 方言对象,用于在 Thymeleaf 中集成 Shiro 标签 return new ShiroDialect(); }测试
2.9.权限不足时跳转到一个页面
未跳转:
实现跳转:
创建MyExceptionHandler
@ControllerAdvice @Slf4j public class MyExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String authorizationException(Exception e){ log.error("异常的内容====="+e.getMessage()); return "403" ; } }创建403.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 权限不足~~~~ </body> </html>测试
3.springboot整合shiro----前后端分离
创建Result
@Data @NoArgsConstructor @AllArgsConstructor public class Result { private Integer code; private String msg; private Object data; }3.1.登录成功或失败---返回json数据
修改LoginController
测试:
3.2.权限不足时---返回json数据
修改MyExceptionHandler
测试
3.3.未登录时---返回json数据
添加依赖
<!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency>创建LoginFilter
public class LoginFilter extends FormAuthenticationFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //设置响应的内容类型为JSON,并使用UTF-8编码 response.setContentType("application/json;charset=utf-8"); // 获取用于写入响应的PrintWriter对象 PrintWriter writer = response.getWriter(); // 创建一个Result对象,包含401状态码和提示信息 Result result = new Result(401, "请先登录---", null); // 将Result对象转换为JSON字符串 String jsonString = JSON.toJSONString(result); // 将JSON字符串写入响应 writer.println(jsonString); // 刷新并关闭PrintWriter对象 writer.flush(); writer.close(); // 返回false,表示请求应在此处停止 return false; } }修改ShiroConfig
测试,不登录,直接访问:
4.shiro权限对象缓存到redis中
引入依赖
<!--shiro和redis整合的依赖--> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>3.3.1</version> </dependency>修改 ShiroConfig
测试
5.使用Swagger2接口文档测试
引入依赖
<!--swagger的依赖引入--> <dependency> <groupId>io.github.jianzhichun</groupId> <artifactId>spring-boot-starter-swagger2</artifactId> <version>0.0.1</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency>创建swagger配置文件
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration //swagger配置文件 public class SwaggerConfig { @Bean //加在方法上,表示把方法的返回结果交于spring容器来管理该对象,里面封装了接口文档的信息 public Docket docket() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .groupName("qy165第五组") .apiInfo(getInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.wqg.controller")) .build(); return docket; } private ApiInfo getInfo() { Contact DEFAULT_CONTACT = new Contact("张三", "151******", "319***7594@qq.com"); ApiInfo apiInfo = new ApiInfo("学生管理系统API文档", "学生管理系统API文档", "2.0", "http://localhost:8080/doc.html", DEFAULT_CONTACT, "游戏公司", "www.4399.com"); return apiInfo; } }设置放行
测试http://localhost:8080/doc.html

















3286

被折叠的 条评论
为什么被折叠?



