Shiro简单demo

2019-08-05  本文已影响0人  dwwl

参考Blog :http://wiki.jikexueyuan.com/project/shiro/authentication.html

执行流程:

  1. 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;

  2. SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;

  3. Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;

  4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;

  5. Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

  6. public class MyRealm1 implements Realm {
        @Override
        public String getName() {
            return "myrealm1";
        }
        @Override
        public boolean supports(AuthenticationToken token) {
            //仅支持UsernamePasswordToken类型的Token
            return token instanceof UsernamePasswordToken; 
        }
        @Override
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String username = (String)token.getPrincipal();  //得到用户名
            String password = new String((char[])token.getCredentials()); //得到密码
            if(!"zhang".equals(username)) {
                throw new UnknownAccountException(); //如果用户名错误
            }
            if(!"123".equals(password)) {
                throw new IncorrectCredentialsException(); //如果密码错误
            }
            //如果身份认证验证成功,返回一个AuthenticationInfo实现;
            return new SimpleAuthenticationInfo(username, password, getName());
        }
    }
    
    img

以后一般继承 AuthorizingRealm(授权)即可;其继承了 AuthenticatingRealm(即身份验证),而且也间接继承了 CachingRealm(带有缓存实现)。

JDBC Realm 使用

最简单的对角色 权限进行控制的demo

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mpt</groupId>
    <artifactId>bootshirodemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bootshirodemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?serverTimezone=GMT
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password:
  main:
    allow-bean-definition-overriding: true
server:
  port: 9001
  tomcat:
    uri-encoding: utf-8
mybatis:
  mapper-locations: mappers/*Mapper.xml
logging:
  level:
    com:
      mpt:
        bootshirodemo: DEBUG

BootshirodemoApplication.java

package com.mpt.bootshirodemo;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;

@SpringBootApplication
public class BootshirodemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootshirodemoApplication.class, args);
    }

    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        //1、定义一个convert转换消息的对象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //2、添加fastjson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        //3、在convert中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //4、将convert添加到converters中
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);
    }
}

这里用的fastJson用于mvc数据传输接收时 对象与json之间的转换,具体的现在还要学习一下。

UserRealm.java

package com.mpt.bootshirodemo.realm;

import com.mpt.bootshirodemo.po.SysUser;
import com.mpt.bootshirodemo.service.SysPermissionService;
import com.mpt.bootshirodemo.service.SysUserService;
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.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.java2d.pipe.SpanShapeRenderer;

import java.util.HashSet;
import java.util.List;

/**
 * @author huangQiChang
 * @date 2019/8/5
 */
@Component
public class UserRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysPermissionService sysPermissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        logger.info("doGetAuthorizationInfo....");
        SysUser sysUSer = (SysUser) principals.getPrimaryPrincipal();
        List<String> permissions = sysPermissionService.selectPermissionByUserId(String.valueOf(sysUSer.getUserId()));

        HashSet<String> permissionsSet = new HashSet<>(permissions);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permissionsSet);//setRoles方法用户设置用户所拥有的角色。
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        SysUser sysUser = sysUserService.findByUserName(token.getUsername());

        if (sysUser == null) {
            return null;
        }
        logger.info("doGetAuthenticationInfo....");
        return new SimpleAuthenticationInfo(sysUser, sysUser.getPassword().toCharArray(), ByteSource.Util.bytes(sysUser.getSalt()), getName());
    }
}

ShiroConfig.java

package com.mpt.bootshirodemo;

import com.mpt.bootshirodemo.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
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 java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description
 * @Author sgl
 * @Date 2018-06-11 17:23
 */
@Configuration
public class ShiroConfig {

    /**
     * 凭证匹配器
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //md5加密1次
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(1);
        return hashedCredentialsMatcher;
    }

    /**
     * 自定义realm
     *
     * @return
     */
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

    /**
     * 安全管理器
     * 注:使用shiro-spring-boot-starter 1.4时,返回类型是SecurityManager会报错,直接引用shiro-spring则不报错
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }


    /**
     * 设置过滤规则
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");

        //注意此处使用的是LinkedHashMap,是有顺序的,shiro会按从上到下的顺序匹配验证,匹配了就不再继续验证
        //所以上面的url要苛刻,宽松的url要放在下面,尤其是"/**"要放到最下面,如果放前面的话其后的验证规则就没作用了。
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/captcha.jpg", "anon");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
}

TestController.java

@RestController
public class TestController {

//    @RequiresRoles("普通用户")
    @RequiresPermissions("systemUserList")
    @GetMapping("/testPerm")
    public String testPerm() {
        return "存在menu权限";
    }
}

md5加密处理

package com.mpt.bootshirodemo;

import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;

/**
 * @author huangQiChang
 * @date 2019/8/5
 */
public class ShiroMD5 {
    //加密方式
    private final static String HASHMODE = "Md5";
    //加密次数
    private final static int SALTNUM = 1;

    public static Object shiroMD5(String mySalt, String pwd) {
        String hashAlgorithmName = HASHMODE;
        //"123456";
        Object credentials = pwd;
        //以用户名作为盐加密
        Object salt = ByteSource.Util.bytes(mySalt);
        int hashIterations = SALTNUM;
        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        return result;
    }

    public static void main(String[] args) {
        System.out.println(shiroMD5("1","1"));
    }
}

上一篇下一篇

猜你喜欢

热点阅读