-
原项目继续添加依赖
<!--shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency> <!--shiro和thymeleaf整合包--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
-
自定义UserRealm类用于认证和授权
package com.jx.config; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.jx.pojo.User; import com.jx.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.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import java.util.Arrays; import java.util.HashSet; import java.util.Set; //自定义Realm public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; //执行授权逻辑 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("执行了=>授权逻辑PrincipalCollection"); Subject subject = SecurityUtils.getSubject(); // User currentUser = (User)subject.getPrincipal();//获取认证用户信息 强制转换失败,未知bug,暂无解决方式 Session session = subject.getSession(); User currentUser = (User) session.getAttribute("currentUser");//从session中读取user String permsArray[] = currentUser.getPerms().split(","); System.out.println("获取权限" + permsArray); Set<String> permsSet = new HashSet<>(Arrays.asList(permsArray));//以“,”分割权限并转为set SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//授权信息类 info.setStringPermissions(permsSet);//使认证的用户具有访问权限 return info; } //执行认证逻辑 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=>认证逻辑AuthenticationToken"); UsernamePasswordToken userToken = (UsernamePasswordToken) token;//用户输入的数据 QueryWrapper<User> wrapper = new QueryWrapper<>();//使用mybatisplus条件构造器进行查询 wrapper.eq("username", userToken.getUsername()); User user = userService.getOne(wrapper); if (user == null) { return null;//数据库中不存在此用户名抛出用户名异常 } Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); session.setAttribute("currentUser", user);//将user存入session String password = user.getPassword(); return new SimpleAuthenticationInfo("", password, "");//验证密码是否匹配,否则抛出密码错误异常 } }
-
ShiroConfig配置类用于注册Bean和对请求进行拦截
package com.jx.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 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; @Configuration public class ShiroConfig { //注册自定义类 @Bean public UserRealm userRealm() { return new UserRealm(); } //创建 DefaultWebSecurityManager @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联Realm securityManager.setRealm(userRealm); return securityManager; } //创建 ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); /* 添加Shiro内置过滤器,常用的有如下过滤器: anon: 无需认证就可以访问 authc: 必须认证才可以访问 user: 如果使用了记住我功能就可以直接访问 perms: 拥有某个资源权限才可以访问 role: 拥有某个角色权限才可以访问 */ Map<String,String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/level1/**","perms[vip1]");// filterMap.put("/level2/**","perms[vip2]"); filterMap.put("/level3/**","perms[vip3]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); shiroFilterFactoryBean.setLoginUrl("/toLogin");//修改到要跳转的login页面; return shiroFilterFactoryBean; } //整合shiro-thymeleaf @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
-
修改User实体类,增加权限属性,数据库增加perms列
package com.jx.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String username; private String password; private String neckname; private String perms;//增加权限属性 }
-
UserMapper
package com.jx.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.jx.pojo.User; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserMapper extends BaseMapper<User>{ }
-
UserService
package com.jx.service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.jx.mapper.UserMapper; import com.jx.pojo.User; import org.springframework.stereotype.Service; @Service("userService") public class UserService extends ServiceImpl<UserMapper,User> { }
-
Controller
package com.jx.controller; import com.jx.service.UserService; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; //@RestController//返回字符串 @Controller public class HelloController { @Autowired private UserService userService; @RequestMapping({"/index"}) public String hello() { return "index"; } @RequestMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password);//封装用户数据 try { subject.login(token);//执行登录方法 return "index";//登录成功 } catch (UnknownAccountException e) { System.out.println("用户名不存在"); model.addAttribute("msg", "用户名不存在!"); return "login";//登陆失败 } catch (IncorrectCredentialsException e) { System.out.println("密码错误"); model.addAttribute("msg", "密码错误!"); return "login";//登陆失败 } } @RequestMapping("/toLogin") public String toLogin() { return "/login"; } @RequestMapping("level1/{id}") public String toMain1(@PathVariable("id") int id) { return "views/level1/" + id; } @RequestMapping("level2/{id}") public String toMain2(@PathVariable("id") int id) { return "views/level2/" + id; } @RequestMapping("level3/{id}") public String toMain3(@PathVariable("id") int id) { return "views/level3/" + id; } //注销登录 @RequestMapping("/logout") public String logout() { Subject currentUser = SecurityUtils.getSubject(); currentUser.getSession().removeAttribute("currentUser"); currentUser.logout(); return "/login"; } }
-
index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>首页</title> <!--semantic-ui--> <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet"> <link th:href="@{/qinjiang/css/qinstyle.css}" rel="stylesheet"> </head> <body> <!--主容器--> <div class="ui container"> <div class="ui segment" id="index-header-nav" th:fragment="nav-menu"> <div class="ui secondary menu"> <a class="item" th:href="@{/index}">首页</a> <div class="right menu"> <!--未登录--> <div th:if="${session.currentUser==null}"> <a class="item" th:href="@{/toLogin}"> <i class="address card icon"></i> 登录 </a> </div> <div th:if="${session.currentUser!=null}"> <a class="item" > 欢迎您:<span>[[${session.currentUser.username}]]</span> </a> </div> <div th:if="${session.currentUser!=null}"> <a class="item" th:href="@{/logout}"> <i class="sign-out icon"></i> 注销 </a> </div> </div> </div> </div> <div class="ui segment" style="text-align: center"> <h3>Shiro Study </h3> </div> <div> <br> <div class="ui three column stackable grid"> <div class="column" shiro:hasPermission='vip1'> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 1</h5> <hr> <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div> <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div> <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div> </div> </div> </div> </div> <div class="column" shiro:hasPermission='vip2'> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 2</h5> <hr> <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div> <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div> <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div> </div> </div> </div> </div> <div class="column" shiro:hasPermission='vip3'> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 3</h5> <hr> <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div> <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div> <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div> </div> </div> </div> </div> </div> </div> </div> <script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script> <script th:src="@{/qinjiang/js/semantic.min.js}"></script> </body> </html>
-
权限控制实现效果
root1:具有vip1权限
root2:具有vip1,vip2权限
root3:具有vip1,vip2,vip3权限