赞
踩
1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
1、首先调用Subject.isPermitted接口
2 调用相应的Realm获取主题相应的角色/权限;
3、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted会返回true,否则返回false表示授权失败。
完整代码地址:https://gitee.com/bseaworkspace/springboot2all/tree/master/SpringBootShiroAuthorization
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>SpringBoot2</artifactId> <groupId>zz</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>SpringBootShiroAuthorization</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--目的:《可选》引入springboot 热启动,每次修改以后,会自动把改动加载,不需要重启服务了--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <!-- 添加JPA的支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 添加测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- shiro-spring --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> <scope>provided</scope> </dependency> </dependencies> <repositories> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.properties
server.port=9087
server.servlet.context-path=/r
# 数据库的信息
spring.datasource.url = jdbc:mysql://localhost:3306/java10?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = Java20190713*yy
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.jpa.database = MYSQL
# spring.jpa.show-sql = true 表示会在控制台打印执行的sql语句
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
三个实体类,
注意:
权限实体类
package com.zz.entity; import lombok.Data; import org.hibernate.annotations.Proxy; import javax.persistence.*; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @Description: java类作用描述 * @Author: Bsea * @CreateDate: 2019/8/31$ 15:54$ */ @Entity @Table(name="T_PERMISSION") @Proxy(lazy = false) public class Permission implements Serializable { final static long serialVersionUID=23434243325424l; @Id @Column(length = 50) private String id; //url地址 private String url; //url描述 private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
角色实体类
package com.zz.entity; import lombok.Data; import org.hibernate.annotations.Proxy; import javax.persistence.*; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @Description: java类作用描述 * @Author: Bsea * @CreateDate: 2019/8/31$ 15:54$ */ @Entity @Table(name="T_ROLE") @Proxy(lazy = false) public class Role implements Serializable { final static long serialVersionUID=234345424l; @Id @Column(length = 50) private String id; //角色描述 private String detail; //角色名称 private String name; // @ManyToMany注释表示Teacher是多对多关系的一端。 // @JoinTable描述了多对多关系的数据表关系。name属性指定中间表名称,joinColumns定义中间表与Teacher表的外键关系。 // 中间表Teacher_Student的Teacher_ID列是Teacher表的主键列对应的外键列,inverseJoinColumns属性定义了中间表与另外一端(Student)的外键关系。 @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) @JoinTable(name = "T_ROLE_PERMISSION", joinColumns = { @JoinColumn(name = "r_id") }, inverseJoinColumns = { @JoinColumn(name = "p_id") }) private Set<Permission> permissions = new HashSet<Permission>(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Permission> getPermissions() { return permissions; } public void setPermissions(Set<Permission> permissions) { this.permissions = permissions; } }
用户实体类
package com.zz.entity; import lombok.Data; import org.hibernate.annotations.Proxy; import java.io.Serializable; import java.sql.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.*; @Entity @Table(name="T_USER") @Proxy(lazy = false) public class User implements Serializable{ final static long serialVersionUID=23424l; @Id @Column(length = 50) private String id; //用户名 private String username; private String passwd; //是否有效 1:有效 0:锁定 private String status; //创建时间 private Date createTime; //使用 @ManyToMany 注解来映射多对多关联关系 //使用 @JoinTable 来映射中间表 //1. name 指向中间表的名字 //2. joinColumns 映射当前类所在的表在中间表中的外键 //2.1 name 指定外键列的列名 //2.2 referencedColumnName 指定外键列关联当前表的哪一列 //3. inverseJoinColumns 映射关联的类所在中间表的外键 // @ManyToMany注释表示Teacher是多对多关系的一端。 // @JoinTable描述了多对多关系的数据表关系。name属性指定中间表名称,joinColumns定义中间表与Teacher表的外键关系。 // 中间表Teacher_Student的Teacher_ID列是Teacher表的主键列对应的外键列,inverseJoinColumns属性定义了中间表与另外一端(Student)的外键关系。 @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) @JoinTable(name = "T_USER_ROLE", joinColumns = { @JoinColumn(name = "u_id") }, inverseJoinColumns = { @JoinColumn(name = "r_id") }) private Set<Role> roles = new HashSet<Role>(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
Shiro
package com.zz.config; import java.util.LinkedHashMap; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/register.html", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/user/register", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } /** * cookie对象 * @return */ public SimpleCookie rememberMeCookie() { // 设置cookie名称,对应login.html页面的<input type="checkbox" name="rememberMe"/> SimpleCookie cookie = new SimpleCookie("rememberMe"); // 设置cookie的过期时间,单位为秒,这里为一天 cookie.setMaxAge(86400); return cookie; } /** * cookie管理对象 * @return */ public CookieRememberMeManager rememberMeManager() { //Cookie 数据存在客户端的浏览器 CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); // rememberMe cookie加密的密钥 cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
package com.zz.config; import javax.annotation.Resource; import com.zz.entity.Permission; import com.zz.entity.Role; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.zz.entity.User; import com.zz.repository.UserRepository; import java.util.HashSet; import java.util.List; import java.util.Set; //import com.springboot.dao.UserMapper; //import com.springboot.pojo.User; @Slf4j public class ShiroRealm extends AuthorizingRealm { @Resource private UserRepository userRepository; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUsername(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 Set<String> roleSet = new HashSet<String>(); Set<Permission> permissionList= new HashSet<Permission>(); Set<Role> roles=user.getRoles(); for (Role r : roles) { roleSet.add(r.getName()); permissionList.addAll(r.getPermissions()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 Set<String> permissionSet = new HashSet<String>(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); // User user = userMapper.findByUserName(userName); User user = userRepository.findByUsername(userName); // User user=new User(); if (user == null) { throw new UnknownAccountException("用户名错误!"); } //1. MD5加密不可以破解 //2. 登录比较的是,两个密文 if (!password.equals(user.getPasswd())) { throw new IncorrectCredentialsException("密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } }
Controller
package com.zz.controller; import javax.annotation.Resource; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.zz.entity.User; import com.zz.pojo.ResponseBo; import com.zz.service.UserService; import com.zz.util.KeyUtil; import com.zz.util.MD5Utils; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList() { return "/index1.html"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "/index1.html"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "/index1.html"; } @Resource UserService userService; @GetMapping("/register") public String login() { return "register.html"; } @PostMapping("/register") @ResponseBody public ResponseBo register(User user) { String password = MD5Utils.encrypt(user.getUsername(), user.getPasswd()); user.setPasswd(password); user.setId(KeyUtil.genUniqueKey()); userService.save(user); return ResponseBo.ok(); } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index1.html"; } @PostMapping("/getlogin") @ResponseBody public User getLoginUser(){ return (User) SecurityUtils.getSubject().getPrincipal(); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。