renren-fast权限管理shiro框架实现细节

实现

主要理解一下这个项目中是如何实现权限的认证和鉴权的,以及shrio的@RequiresPermissions注解,

controller层

根据登录操作传入用户信息,然后根据ID生成信息返回给前端的一个token,前端拿到这个token之后,后面的请求都会带着这个token。

src/main/java/io/renren/modules/sys/controller/SysLogController.java

/**
	 * 登录
	 */
	@PostMapping("/sys/login")
	public Map<String, Object> login(@RequestBody SysLoginForm form)throws IOException {
    
    
		boolean captcha = sysCaptchaService.validate(form.getUuid(), form.getCaptcha());
		if(!captcha){
    
    
			return R.error("验证码不正确");
		}

		//用户信息
		SysUserEntity user = sysUserService.queryByUserName(form.getUsername());

		//账号不存在、密码错误
		if(user == null || !user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())) {
    
    
			return R.error("账号或密码不正确");
		}

		//账号锁定
		if(user.getStatus() == 0){
    
    
			return R.error("账号已被锁定,请联系管理员");
		}

		//生成token,并保存到数据库
		R r = sysUserTokenService.createToken(user.getUserId());
		return r;
	}

登录后,前端界面获得的token,前端项目写的也是每次请求的时候都会带着这个token。
在这里插入图片描述

Config 认证和鉴权

认证是在登录的时候调用,鉴权是在调用其他接口的时候使用。
在ShiroConfig配置中。重新自定义了realm对象和过滤器OAuth2Filter,以前前后端未分离通过密码来认证,现在前后端分离通过token来认证。

src/main/java/io/renren/config/ShiroConfig.java

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */

package io.renren.config;

import io.renren.modules.sys.oauth2.OAuth2Filter;
import io.renren.modules.sys.oauth2.OAuth2Realm;
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.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置
 *
 * @author Mark [email protected]
 */
@Configuration
public class ShiroConfig {
    
    

    @Bean("securityManager")
    //自定义realm对象
    public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
    
    
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(oAuth2Realm);
        securityManager.setRememberMeManager(null);
        return securityManager;
    }

    @Bean("shiroFilter")
    //过滤器重新自定义
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    
    
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        //oauth过滤
        Map<String, Filter> filters = new HashMap<>();
        filters.put("oauth2", new OAuth2Filter());
        shiroFilter.setFilters(filters);

        Map<String, String> filterMap = new LinkedHashMap<>();
        //anon表示匿名缩写,这些资源都是放行的
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/druid/**", "anon");
        filterMap.put("/app/**", "anon");
        filterMap.put("/sys/login", "anon");
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/captcha.jpg", "anon");
        filterMap.put("/aaa.txt", "anon");

        //对于其他的统统调用,定义的oauth2这个规则,定义哪些页面放行,哪些页面不放行
        filterMap.put("/**", "oauth2");
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    
    
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    
    
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}


鉴权时,调用其他接口使用shrio一些自带的注解进行鉴权。在其他controller能够看到@RequiresPermissions(“”)注解。请求进入这个接口就会查去后台数据库查用户权限列表。认真你有这个权利后才能访问这个接口。

对应查询用户权限的代码如下,这个权限列表在数据库中可以体现。

//用户权限列表
Set<String> permsSet = shiroService.getUserPermissions(userId);

sys_menu表

在这里插入图片描述

如果在这个表中,你有权限可以操作,那你的请求就可以访问后操作。
给不同的接口可能需要不同的权限,然后在数据库配置好,你就可以实现权限管理了。

	/**
	 * 选择菜单(添加、修改菜单)
	 */
	@GetMapping("/select")
	@RequiresPermissions("sys:menu:select")
	public R select(){
    
    
		//查询列表数据
		List<SysMenuEntity> menuList = sysMenuService.queryNotButtonList();
		
		//添加顶级菜单
		SysMenuEntity root = new SysMenuEntity();
		root.setMenuId(0L);
		root.setName("一级菜单");
		root.setParentId(-1L);
		root.setOpen(true);
		menuList.add(root);
		
		return R.ok().put("menuList", menuList);
	}

认证的时候,是当你进入到你需要去鉴权的这个接口时候,他就会从前端取出这个token来,然后和数据库,对比完信息后再存储起来,后面会缓存到info。

src/main/java/io/renren/modules/sys/oauth2/OAuth2Realm.java

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */

package io.renren.modules.sys.oauth2;

import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.entity.SysUserTokenEntity;
import io.renren.modules.sys.service.ShiroService;
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.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 认证
 *
 * @author Mark [email protected]
 */
@Component
public class OAuth2Realm extends AuthorizingRealm {
    
    
    @Autowired
    private ShiroService shiroService;

    @Override
    public boolean supports(AuthenticationToken token) {
    
    
        return token instanceof OAuth2Token;
    }

    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    
    
        SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
        Long userId = user.getUserId();

        //用户权限列表
        Set<String> permsSet = shiroService.getUserPermissions(userId);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    
        String accessToken = (String) token.getPrincipal();

        //根据accessToken,查询用户信息
        SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);
        //token失效
        if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
    
    
            throw new IncorrectCredentialsException("token失效,请重新登录");
        }

        //查询用户信息
        SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());
        //账号锁定
        if(user.getStatus() == 0){
    
    
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
        return info;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41398619/article/details/127046978
今日推荐