SpringBoot2.0 assembled Shiro

1, shiro's three core concepts:
  1) Subject: represents the user is currently performing an operation, but on behalf of the Subject can be people, it can be any third-party system account. Of course, each subject will be bound to the instance SercurityManger.
  2) SecurityManger: SecurityManager is the core of Shiro, Shiro main coordination within the various security components, we do not need to be too concerned about this, just you need to know that you can set a custom's Realm.
  3) Realm: Shiro bridge user data and data interaction. For example, it requires user authentication, certification authority. They are required to read data by Realm.

2, springboot shiro integrated relatively simple, requires only two classes: one class is ShiroConfig, a custom class Realm.

  1) ShiroConfig categories: shiro in some configurations, xml configuration relative to the previous. Including: ShiroFilterconfiguration, password encryption algorithm, support annotations configuration functions.

  2) Custom Realm categories: inheritance AuthorizingRealm. And override the parent class doGetAuthorizationInfo (certification authority), doGetAuthenticationInfo (identity) of these two methods.

 

3、demo

  Project structure:

  

  rely:

<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指定的无权页面

 

Guess you like

Origin www.cnblogs.com/xy-ouyang/p/11333072.html