SpringBoot2.0集成Shiro

1、shiro的三个核心概念:
  1)Subject:代表当前正在执行操作的用户,但Subject代表的可以是人,也可以是任何第三方系统帐号。当然每个subject实例都会被绑定到SercurityManger上。
  2)SecurityManger:SecurityManager是Shiro核心,主要协调Shiro内部的各种安全组件,这个我们不需要太关注,只需要知道可以设置自定的Realm。
  3)Realm:用户数据和Shiro数据交互的桥梁。比如需要用户身份认证、权限认证。都是需要通过Realm来读取数据。

2、springboot中集成shiro相对简单,只需要两个类:一个是ShiroConfig类,一个是自定义Realm类。

  1)ShiroConfig类:shiro的一些配置,相对于之前的xml配置。包括:ShiroFilter的配置,密码加密的算法,支持注解的配置等功能。

  2)自定义Realm类:继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限认证)、doGetAuthenticationInfo(身份认证)这两个方法。

3、demo

  项目结构:

  

  依赖:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>

  ShiroConfig

package com.oy;

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

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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * @author oy
 * @date 2019年8月10日 下午4:50:55
 * @version 1.0.0
 */
@Configuration
public class ShiroConfig {

    /************************* shiroFilter配置 start *************************/
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/user/login", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/front/**", "anon");
        filterChainDefinitionMap.put("/api/**", "anon");

        filterChainDefinitionMap.put("/admin/**", "authc");
        filterChainDefinitionMap.put("/user/**", "authc");

        // 剩余的都需要认证
        // 这行代码必须放在所有权限设置的最后,不然会导致所有url都被拦截
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(myRealm());
        return defaultSecurityManager;
    }

    @Bean
    public MyRealm myRealm() {
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }
    /************************* shiroFilter配置 end   *************************/
    
    
    /************************* 开启shiro注解配置 start *************************/
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证.
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     */
    @Bean
    @DependsOn({ "lifecycleBeanPostProcessor" })
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
    /************************* 开启shiro注解配置 end   *************************/
}

  MyRealm

package com.oy;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 com.oy.model.User;
import com.oy.service.UserService;

public class MyRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    /**
     * 认证:身份认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        User user = userService.getUserByUsername(username);
        if (user != null) {
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
            return authcInfo;
        } else {
            return null;
        }
    }

    /**
     * 授权:权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //String userName = (String) principals.getPrimaryPrincipal();
        //authorizationInfo.setRoles(userService.getRoles(userName));
        //authorizationInfo.setStringPermissions(userService.getPermissions(userName));
        
        Set<String> stringSet = new HashSet<>();
        stringSet.add("user:view");
        stringSet.add("user:edit");
        authorizationInfo.setStringPermissions(stringSet);
        return authorizationInfo;
    }
}

  

  IndexController

package com.oy.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.oy.util.CryptographyUtil;

/**
 * @author oy
 * @date 2019年8月10日 下午6:21:58
 * @version 1.0.0
 */
@Controller
public class IndexController {

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

    @RequestMapping("/user/login")
    @ResponseBody
    public String doLogin(@RequestParam(value = "username", required = false) String username,
            @RequestParam(value = "password", required = false) String password) {

        System.out.println("username=" + username + ", password=" + password);
        // 从SecurityUtils里边创建一个 subject
        Subject subject = SecurityUtils.getSubject();
        // 在认证提交前准备 token(令牌)
        //UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        UsernamePasswordToken token = new UsernamePasswordToken(username, CryptographyUtil.md5(password, "abc123"));
        // 执行认证登陆
        try {
            subject.login(token);
        } catch (UnknownAccountException uae) {
            return "未知账户";
        } catch (IncorrectCredentialsException ice) {
            return "密码不正确";
        } catch (LockedAccountException lae) {
            return "账户已锁定";
        } catch (ExcessiveAttemptsException eae) {
            return "用户名或密码错误次数过多";
        } catch (AuthenticationException ae) {
            return "用户名或密码不正确!";
        }
        
        if (subject.isAuthenticated()) {
            return "登录成功";
        } else {
            token.clear();
            return "登录失败";
        }
    }
    
    @RequiresPermissions("user:view")
    @GetMapping("/user")
    @ResponseBody
    public String userList() {
        return "user list";
    }
    
    @RequiresPermissions("book:view")
    @GetMapping("/book")
    @ResponseBody
    public String bookList() {
        return "book list";
    }

    @RequestMapping("/unauth")
    public String unauth() {
        return "unauth.html";
    }
}

  login.html

<body>
    <h2>login页面</h2>
    <form action="/user/login" method="post">
        username: <input type="text" name="username" value=""/></br></br>
        password: <input type="text" name="password" value=""/></br>
        <input type="submit" value="submit"/>
    </form>
</body>

  CryptographyUtil

package com.oy.util;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.Md5Hash;

public class CryptographyUtil {

    /**
     * base64加密
     * @param str
     * @return
     */
    public static String encBase64(String str) {
        return Base64.encodeToString(str.getBytes());
    }

    /**
     * base64解密
     * @param str
     * @return
     */
    public static String decBase64(String str) {
        return Base64.decodeToString(str);
    }

    /**
     * Md5加密
     * @param str
     * @param salt
     * @return
     */
    public static String md5(String str, String salt) {
        return new Md5Hash(str, salt).toString();
    }

    public static void main(String[] args) {
        String password = "123456";
        System.out.println("Base64加密:" + CryptographyUtil.encBase64(password));
        System.out.println("Base64解密:" + CryptographyUtil.decBase64(CryptographyUtil.encBase64(password)));

        // a6f70dedd698be90addd35abe38d3876
        System.out.println("Md5加密:" + CryptographyUtil.md5(password, "abc123"));
    }
}

 参考资料:

  1)https://blog.csdn.net/bicheng4769/article/details/86668209

  2)shiro无权限,不跳转到指定页面。setUnauthorizedUrl无效

  3)setUnauthorizedUrl("/403")不起作用,不能设置没有权限的跳转页面

  4)shiro的@RequiresPermissions不生效和无权限跳异常而不是shiro指定的无权页面

猜你喜欢

转载自www.cnblogs.com/xy-ouyang/p/11333072.html
今日推荐