六、Springboot 整合Shiro---04权限控制

本章节基于:五、Springboot 整合Shiro---03认证---第三方QQ登陆

一、通过realm进行权限控制

1、在templates下创建三个html页面

user.html、admin.html、unauthorized.html

2、创建一个Action类

package com.xslde.action;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Map;

/**
 * Created by xslde on 2018/7/21
 */
@Controller
public class PermissionAction {

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

    //拥有user角色才可访问
    @GetMapping("/user")
    public String user(Map<String,String> mode){
        mode.put("msg","拥有user角色");
        return "user.html";
    }

    //拥有user角色才可访问和user:query权限才可访问
    @GetMapping("/user/per")
    public String userPer(Map<String,String> mode){
        mode.put("msg","拥有user角色和user:query权限");
        return "user.html";
    }

    //拥有admin角色才可访问
    @GetMapping("/admin")
    public String admin(Map<String,String> mode){
        mode.put("msg","拥有admin角色");
        return "admin.html";
    }


}

3、在ShiroConf.class中加入上面action类中的请求url权限控制,对shiroFilter方法进行改动,添加拦截url和无权访问跳转页面url

package com.xslde.configurer;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.mgt.SessionManager;
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.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author xslde
 * @Description
 * @Date 2018/7/20 16:25
 */
@Configuration
public class ShiroConf {


    //注入shiro过滤器
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilter(WebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");  // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setSuccessUrl("/index");// 登录成功后要跳转的链接
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");//设置无权限跳转页面
        Map<String, String> chains = new LinkedHashMap<>();
        chains.put("/logout","logout");//登出
        chains.put("/login", "anon");//anon表示可以匿名访问
        chains.put("/login/qq", "anon");//anon表示可以匿名访问
        chains.put("/authorize/qq", "anon");//anon表示可以匿名访问
        //对PermissionAction.class 中的url进行权限控制
        chains.put("/user", "roles[user]");//需要user角色才可以访问
        chains.put("/user/per", "perms[user:query]");//需要user角色才可以访问
        chains.put("/admin", "roles[admin]");//需要admin角色才可以访问
        //chains.put("/**", "authc");//表示需要认证,才能访问
        chains.put("/**", "user");//表示需要认证或记a住我都能访问
        shiroFilterFactoryBean.setFilterChainDefinitionMap(chains);
        return shiroFilterFactoryBean;
    }


    //安全管理其
    @Bean
    public WebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(shiroRealm());
        securityManager.setCacheManager(cacheManager());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    //会话管理器
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionIdUrlRewritingEnabled(true);
        sessionManager.setGlobalSessionTimeout(1 * 60 * 60 * 1000);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdCookie(rememberMeCookie());
        return sessionManager;
    }

    //Realm,里面是自己实现的认证和授权业务逻辑
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    //缓存管理
    @Bean
    public EhCacheManager cacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return cacheManager;
    }

    //密码管理
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5"); //散列算法使用md5
        credentialsMatcher.setHashIterations(2);        //散列次数,2表示md5加密两次
        credentialsMatcher.setStoredCredentialsHexEncoded(true);//启用十六进制存储
        return credentialsMatcher;
    }

    //cookie管理
    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(1 * 60 * 60);
        return cookie;
    }

    //记住我
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //这个地方有点坑,不是所有的base64编码都可以用,长度过大过小都不行,没搞明白,官网给出的要么0x开头十六进制,要么base64
        cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
    return cookieRememberMeManager;
    }
}

4、在ShiroRealm.class 中添加admin角色用户,并在权限控制doGetAuthorizationInfo()方法中添加用户权限控制

package com.xslde.configurer;

import com.xslde.model.mapped.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * @Author xslde
 * @Description
 * @Date 2018/7/20 16:30
 */
public class ShiroRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //给当前用户授权的权限(功能权限、角色)
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //xslde用户拥有user角色
        User user = (User) principals.getPrimaryPrincipal();
        //真实开发中,角色权限从数据库获取
        if (user.getUsername().equals("xslde")){
            //设置该用户拥有user角色
            authorizationInfo.addRole("user");
            //设置该用户拥有delete权限
            authorizationInfo.addStringPermission("user:query");
        }
        //admin用户拥有admin角色
        if (user.getUsername().equals("admin")){
            //设置该用户拥有user角色
            authorizationInfo.addRole("admin");
            //设置该用户拥有delete权限
            authorizationInfo.addStringPermission("admin:delete");
        }


        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户名
        String username = (String) token.getPrincipal();
        //开发中,这里都是去数据库查询
        //做demo,就不查询了
        if (!"xslde".equals(username)&&!"test".equals(username)&&!"xslde.com".equals(username)&&!"admin".equals(username)){
            throw new UnknownAccountException("用户不存在!");
        }
        User user =null;
        if ("xslde".equals(username)){
            user = new User();
            user.setUsername("xslde");
            user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
            user.setSalt("abcd");
            user.setAvailable(1);
        }
        if ("admin".equals(username)){
            user = new User();
            user.setUsername("admin");
            user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
            user.setSalt("abcd");
            user.setAvailable(1);
        }
        if ("test".equals(username)){
            user = new User();
            user.setUsername("test");
            user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
            user.setSalt("abcd");
            user.setAvailable(0);
        }

        //这是模拟数据库里面拥有QQ第三方用户信息
        if ("xslde.com".equals(username)){
            user = new User();
            user.setUsername("xslde.com");
            user.setAvailable(1);
            user.setSalt("abcd");
            user.setPassword("6e20337c6b222fa0a8c3bbb9dd979374");//
        }
        if (user.getAvailable()!=1){
            throw  new LockedAccountException("账户已被锁定");
        }
        return  new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
    }

    //生成一个加盐密码
    public static void main(String[] args) {
        String hashAlgorithmName = "md5";//加密类型
        Integer iteration = 2;//迭代次数
        String password = "123456";
        String salt = "abcd";
        String s = new SimpleHash(hashAlgorithmName,password,salt,iteration).toHex();
        System.out.println(s);
        //加密后的密码
        //0caf568dbf30f5c33a13c56b869259fc

    }
}

完成以上步骤后,启动项目使用admin登陆

单击需要user角色的页面:

显示为该页面,说明权限控制已生效,接下来访问需要admin角色的页面:

推出登陆,换角色为user的"xslde"用户: 

单击需要user角色用的页面:

到此url控制授权完成。

二、通过Shiro注解进行权限控制

1、开启注解权限控制功能

在pom文件中添加aop依赖:

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

在application.yml文件中配置开启aop代理:

spring:
  aop:
  #开启aop代理
    auto: true
    proxy-target-class: true

在ShiroConf.class中添加:


    //开启shiro注解权限控制
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }

在PermissionAction.class中添加几个访问方法,测试注解权限控制是否启用:


    //通过注解控制授权
    @RequiresRoles({"admin"})
    @GetMapping("/abc")
    public String abc(Map<String,String> mode){
        mode.put("msg","拥有admin角色,并且是通过注解控制");
        return "admin.html";
    }

    //通过注解控制权限
    @RequiresPermissions({"user:query"})
    @GetMapping("/abcd")
    public String abcd(Map<String,String> mode){
        mode.put("msg","拥有user:query权限,并且是通过注解控制");
        return "user.html";
    }

2、测试注解是否生效:

启动项目:

注解控制权限生效: 

使用admin角色用户访问:

Shiro还有两种控制方式就不记录了,个人不怎么用:

方式3:标签控制

方式4:编程控制

权限控制到这里就完成了。

项目实例:springboot-example06

猜你喜欢

转载自blog.csdn.net/xslde_com/article/details/81146597