Shiro权限管理框架粗解

Shiro权限管理框架粗解

一.流程

在这里插入图片描述

二.权限管理模型

在这里插入图片描述

用户(用户id,账号、密码…)

权限(权限id,权限名称,访问地址)

角色(角色id,角色名称)

角色和权限关系(角色id、权限id)

用户和角色关系(用户id、角色id)

三.粗细颗粒度

1.什么是粗颗粒度和细颗粒度

​ 对资源类型的管理称为粗颗粒度权限管理,即只控制到菜单、按钮、方法,粗粒度的例子比如:用户具有用户管理的权限,具有导出订单明细的权限。对资源实例的控制称为细颗粒度权限管理,即控制到数据级别的权限,比如:用户只允许修改本部门的员工信息,用户只允许导出自己创建的订单明细。

2.如何实现粗颗粒度和细颗粒度

​ 对于粗颗粒度的权限管理可以很容易做系统架构级别的功能,即系统功能操作使用统一的粗颗粒度的权限管理。

​ 对于细颗粒度的权限管理不建议做成系统架构级别的功能,因为对数据级别的控制是系统的业务需求,随着业务需求的变更业务功能变化的可能性很大,建议对数据级别的权限控制在业务层个性化开发,比如:用户只允许修改自己创建的商品信息可以在service接口添加校验实现,service接口需要传入当前操作人的标识,与商品信息创建人标识对比,不一致则不允许修改商品信息。

四.基于url拦截

在这里插入图片描述

五.Shiro

1.Shiro架构

[外链图片转存失败(img-aplrOLgw-1567323839363)(C:\Users\50304\AppData\Roaming\Typora\typora-user-images\1567322703115.png)]

2.Subject

Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

3.SecurityManager

SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。

SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。

4.Authenticator

Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

5.Authorizer

Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

6.Realm

Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。

注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

7.sessionManager

sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

8.SessionDAO

SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

9.CacheManager

CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。

10.Cryptography

Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

六.实现

1.ShiroConfig


@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;
	}

	/**
	 * 设置securityManager
	 * @return
	 */
	@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;
	}
	
	/**
	 * 认证设置
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
}

注:filterChainDefinitionMap.put(“”,“”)中的参数

​ anon 无需认证

​ authc 需要认证

​ user 如果使用rememberme可以直接访问

​ perms 必须得到资源权限

​ role 必须得到角色权限

2.ShiroRealm

@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;
	}

}

3.实体类

实体类使用jpa建立并且实现多对多连接

1)用户类

@Entity
@Table(name="T_USER")

@Proxy(lazy = false)
public class User implements Serializable{
	@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;
	}
}

2)角色类
@Entity
@Table(name="T_ROLE")

@Proxy(lazy = false)
public class Role {

    @Id
    @Column(length = 50)
    private String id;
    //角色描述
    private String detail;
    //角色名称
    private String name;

    @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>();



    @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
    @JoinTable(name = "T_USER_ROLE", joinColumns = { @JoinColumn(name = "r_id") },
            inverseJoinColumns = {
                    @JoinColumn(name = "u_id") })
    private List<User> users=new ArrayList<User>();


    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;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

3)权限类
@Entity
@Table(name="T_PERMISSION")
@Proxy(lazy = false)
public class Permission {

    @Id
    @Column(length = 50)
    private String id;
    //url地址
    private String url;
    //url描述
    private String name;

    @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
    @JoinTable(name = "T_ROLE_PERMISSION", joinColumns = { @JoinColumn(name = "p_id") }, inverseJoinColumns = {
            @JoinColumn(name = "r_id") })
    private List<Role> roles=new ArrayList<>();


    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;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
}

4.Controller

1)登陆controller
@Controller
public class LoginController {

	@GetMapping("/login")
	public String login() {
		return "login1.html";
	}

	@PostMapping("/login")
	@ResponseBody
	public ResponseBo login(String username, String password, Boolean rememberMe) {
		
		password = MD5Utils.encrypt(username, password);
		UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
		Subject subject = SecurityUtils.getSubject();
		try {
			subject.login(token);
			return ResponseBo.ok();
		} catch (UnknownAccountException e) {
			return ResponseBo.error(e.getMessage());
		} catch (IncorrectCredentialsException e) {
			return ResponseBo.error(e.getMessage());
		} catch (LockedAccountException e) {
			return ResponseBo.error(e.getMessage());
		} catch (AuthenticationException e) {
			return ResponseBo.error("认证失败!");
		}
	}

	@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();
	}
}
2)用户controller


@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();
	}
}

注:@RequiresPermissions(“user:add”)以此设置权限名称

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值