springboot+shiro入门篇

shiro分两篇文章写,应该分三篇来写,第一篇写各种概念和shiro执行流程,框架图这些的,但这些网上太多,我就不写了,主要侧重点在于实际应用。如果不看这个入门篇,进阶篇可能会看不懂,当然高手随便。文章中概念都是网上查阅后复制粘贴的,如有雷同,很是正常。代码为自己编写亲自测试,保证质量。此刻应有掌声~~

1、概念

    shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证,授权,加密,会话管理。Shiro首要的和最重要的目标就是容易使用并且容易理解。

从大的角度来看,Shiro有三个主要的概念:SubjectSecurityManagerRealms后面还有个比较重要的filter需要配置,先了解一下这三个概念:

Subject主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,是一个比较抽象的概念,从代码角度来看比较容易理解。所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

2、名词解释:

Authentication身份认证/登录,验证用户是不是拥有相应的身份;

Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

3、上代码(pom文件后面粘上,不属于重点,User类,Role类全是根据项目数据库表定义的,文章后面也会粘出来)

  3.1  首先shiro认证,授权不是集成了jar包就自己可以去认证,授权了,那样的话也太厉害了。所以首先先要告诉shiro是哪个用户登录上来了,然后再告诉shiro这个用户具有什么角色(角色来决定权限)。这些信息都给shiro了,shiro这个时候就会自动给你校验用户是否合法或是否有权限了。

     3.1.1 如何告诉shiro是哪个用户呢,肯定是用户登录的时候告诉了。controller里面写了两个接口一个登录,一个测试,后续配置路径时就是这个接口路径。

   3.1.2  上一步是告诉shiro用户来了,你开始工作了,那么怎么工作呢,shiro目前只知道登录的用户信息,如果验证是否合法肯定还要知道数据库的所有用户信息,此时它才能进行校验是否该用户存在或者合法。所以需要自定义AuthorizingRealm类,注意这个是必须要自定义的,不是我自己想去自定义的哈。

controller层

/**
 * @author WYH
 * @date 2019/3/19 11:30
 */
@RestController
@RequestMapping("user")
public class UserControll {

    @GetMapping("login")
    public Object login(){
        User user = new User();
        user.setUserName("wenyonghui");
        user.setPassWord("123456");
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassWord());
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        User u = (User) subject.getPrincipal();
        return getMessageMap(u);
    }

    @GetMapping("test01")
    public Object test01(){
        return getMessageTestMap("test01");
    }


    public Map<String,Object> getMessageMap(User user){
        Map map = new HashMap();
        map.put("code","0");
        map.put("message","登录成功");
        map.put("user",user);
        return map;
    }

    public Map<String,Object> getMessageTestMap(String message){
        Map map = new HashMap();
        map.put("code","0");
        map.put("message",message);
        return map;
    }

}

自定义AuthorizingRealm

/**
 * @author WYH
 * @date 2019/3/19 11:02
 */
public class UserRealm extends AuthorizingRealm {
    /**
     * @description 登录
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        //TODO 根据username从数据库中查询user数据,这里做模拟user实体。
        User user = new User();
        user.setUserName("wenyonghui");
        user.setPassWord("123456");
        Role role = new Role();
        Set<String> roleSet = new HashSet<>();
        roleSet.add("admin");
        role.setRole(roleSet);
        user.setRole(role);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassWord(),getName());
        System.out.println("开始认证");
        return info;
    }

    /**
     * @description 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> role = user.getRole().getRole();
        info.setRoles(role);
        return info;
    }
}

3.1.3 完成上面两部其实已经差不多了,但此时只是做了告诉shiro登录的用户信息,和shiro从根据用户信息从数据库中查数据库中的用户信息,表面上看已经可以进行校验。但此时shiro还无法进行校验,因为项目中根本不知道你要用shiro来校验啊,校验规则是什么啊。所以此时需要对shiro进行配置,此类需要@Configuration注解,整体大环境是springboot,添加这个注解会自动装配,不多解释。

shirocongfiguration

package com.dx.shiro.shiro_deom.config;

import com.dx.shiro.shiro_deom.Test.RedisSessionDao;
import com.dx.shiro.shiro_deom.filter.CustomRolesAuthorizationFilter;
import com.dx.shiro.shiro_deom.usershiro.UserRealm;
import org.apache.shiro.mgt.SecurityManager;
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.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro 配置类
 * @author tianguifang
 *
 */
@Configuration
public class ShiroConfiguration {

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(myRealm());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    @Bean
    public DefaultWebSessionManager getSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(getRedisSession());
        sessionManager.setDeleteInvalidSessions(true);// 删除过期的session
        sessionManager.setSessionValidationSchedulerEnabled(true);// 是否定时检查session
        return sessionManager;
    }


    @Bean
    public UserRealm myRealm(){
        return new UserRealm();
    }
    

    public CustomRolesAuthorizationFilter getRolesAuthorization(){
        return new CustomRolesAuthorizationFilter();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> map = new HashMap<>();
        map.put("rolesOrFilter",getRolesAuthorization());
        shiroFilterFactoryBean.setFilters(map);
        // 权限控制map.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/user/login","anon");
        filterChainDefinitionMap.put("/user/test01","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * cookie对象;
     * @return
     */
    public SimpleCookie rememberMeCookie(){
       //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
       SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
       //<!-- 记住我cookie生效时间30天 ,单位秒;-->
       simpleCookie.setMaxAge(60);
       return simpleCookie;
    }

    /**
     * cookie管理对象;记住我功能
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
       CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
       cookieRememberMeManager.setCookie(rememberMeCookie());
       //rememberMe cookie加密的密钥 默认AES算法 下面三行代码是用来获取秘钥的
//        KeyGenerator keygen = KeyGenerator.getInstance("AES");
//        SecretKey deskey = keygen.generateKey();
//        System.out.println(org.apache.shiro.codec.Base64.encodeToString(deskey.getEncoded()));
       cookieRememberMeManager.setCipherKey(Base64.getDecoder().decode("QxxW3vZvJtHjS4wknND81g=="));
       return cookieRememberMeManager;
    }

}

3.1.4 完成上面三部,一个基本的shiro登录和权限校验都完成了,是不是很简单。运行起来项目,可以先不登录直接访问test01接口试试,然后登录再访问test01。你会发现真的可以拦截和校验。

4、项目的基本配置 pom和User,Role类供参看

pom文件

<?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.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dx.shiro</groupId>
    <artifactId>shiro_deom</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro_deom</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <shiro.version>1.4.0-RC2</shiro.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.4.8</version>
        </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-cas</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-ehcache</artifactId>
        <version>${shiro.version}</version>
    </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

User实体类

package com.dx.shiro.shiro_deom.model;

import java.io.Serializable;

/**
 * @author WYH
 * @date 2019/3/19 11:20
 */
public class User implements Serializable {
    private String userName;
    private String passWord;
    private Role role;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

Role实体类

package com.dx.shiro.shiro_deom.model;

import java.io.Serializable;
import java.util.Set;

/**
 * @author WYH
 * @date 2019/3/19 11:23
 */
public class Role implements Serializable {
    private Set<String> role;

    public Role() {
    }

    public Set<String> getRole() {
        return role;
    }

    public void setRole(Set<String> role) {
        this.role = role;
    }
}

下一篇写一下进阶篇,主要写:①.限制角色访问的路径,也就是特定的路径只能对特定的角色访问。②.一个用户拥有多个角色,不同角色又对应不同访问路径,此时该如何配置和处理。

(此文章为我工作几年来第一篇技术博客,以后会坚持写,此处做个标记,以便几年后回来看看如今的自己是多菜)

猜你喜欢

转载自blog.csdn.net/qq_34297563/article/details/88974727