一起来学SpringBoot(十六)优雅的整合Shiro

Apache Shiro是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理。借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序 - 从最小的移动应用程序到最大的Web和企业应用程序。网上找到大部分文章都是以前SpringMVC下的整合方式,很多人都不知道shiro提供了官方的starter可以方便地跟SpringBoot整合。

请看shiro官网关于springboot整合shiro的链接:Integrating Apache Shiro into Spring-Boot Applications

整合准备

这篇文档的介绍也相当简单。我们只需要按照文档说明,然后在spring容器中注入一个我们自定义的Realm,shiro通过这个realm就可以知道如何获取用户信息来处理鉴权(Authentication),如何获取用户角色、权限信息来处理授权(Authorization)。如果是web应用程序的话需要引入shiro-spring-boot-web-starter,单独的应用程序的话则引入shiro-spring-boot-starter

依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.4.0-RC2</version>
</dependency>

用户实体

首先创建一个用户的实体,用来做认证

package com.maoxs.pojo;

import lombok.Data;

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

@Data
public class User  implements Serializable {
   
    private Long uid;       // 用户id
    private String uname;   // 登录名,不可改
    private String nick;    // 用户昵称,可改
    private String pwd;     // 已加密的登录密码
    private String salt;    // 加密盐值
    private Date created;   // 创建时间
    private Date updated;   // 修改时间
    private Set<String> roles = new HashSet<>();    //用户所有角色值,用于shiro做角色权限的判断
    private Set<String> perms = new HashSet<>();    //用户所有权限值,用于shiro做资源权限的判断
}

这里了为了方便,就不去数据库读取了,方便测试我们把,权限信息,角色信息,认证信息都静态模拟下。

Resources

package com.maoxs.service;

import org.springframework.stereotype.Service;

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

@Service
public class ResourcesService {
   
    /**
     * 模拟根据用户id查询返回用户的所有权限
     *
     * @param uid
     * @return
     */
    public Set<String> getResourcesByUserId(Long uid) {
   
        Set<String> perms = new HashSet<>();
        //三种编程语言代表三种角色:js程序员、java程序员、c++程序员
        //docker的权限
        perms.add("docker:run");
        perms.add("docker:ps");
        //maven的权限
        perms.add("mvn:debug");
        perms.add("mvn:test");
        perms.add("mvn:install");
        //node的权限
        perms.add("npm:clean");
        perms.add("npm:run");
        perms.add("npm:test");
        return perms;
    }

}

Role

package com.maoxs.service;

import org.springframework.stereotype.Service;

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

@Service
public class RoleService {
   

    /**
     * 模拟根据用户id查询返回用户的所有角色
     *
     * @param uid
     * @return
     */
    public Set<String> getRolesByUserId(Long uid) {
   
        Set<String> roles = new HashSet<>();
        //这里用三个工具代表角色
        roles.add("docker");
        roles.add("maven");
        roles.add("node");
        return roles;
    }

}

User

package com.maoxs.service;

import com.maoxs.pojo.User;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Random;

@Service
public class UserService {
   

    /**
     * 模拟查询返回用户信息
     *
     * @param uname
     * @return
     */
    public User findUserByName(String uname) {
   
        User user = new User();
        user.setUname(uname);
        user.setNick(uname + "NICK");
        user.setPwd("J/ms7qTJtqmysekuY8/v1TAS+VKqXdH5sB7ulXZOWho=");//密码明文是123456
        user.setSalt("wxKYXuTPST5SG0jMQzVPsg==");//加密密码的盐值
        user.setUid(new Random().nextLong());//随机分配一个id
        user.setCreated(new Date());
        return user;
    }
}

认证

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

Realm

package com.maoxs.realm;

import com.maoxs.cache.MySimpleByteSource;
import com.maoxs.pojo.User;
import com.maoxs.service.ResourcesService;
import com.maoxs.service.RoleService;
import com.maoxs.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 这个类是参照JDBCRealm写的,主要是自定义了如何查询用户信息,如何查询用户的角色和权限,如何校验密码等逻辑
 */
public class CustomRealm extends AuthorizingRealm {
   

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private ResourcesService resourcesService;

    //告诉shiro如何根据获取到的用户信息中的密码和盐值来校验密码
    {
   
        //设置用于匹配密码的CredentialsMatcher
        HashedCredentialsMatcher hashMatcher = new HashedCredentialsMatcher();
        hashMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        hashMatcher.setStoredCredentialsHexEncoded(false);
        hashMatcher.setHashIterations(1024);
        this.setCredentialsMatcher(hashMatcher);
    }


    //定义如何获取用户的角色和权限的逻辑,给shiro做权限判断
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
   
        //null usernames are invalid
        if (principals == null) {
   
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        User user = (User) getAvailablePrincipal(principals);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        System.out.println("获取角色信息:" + user.getRoles());
        System.out.println("获取权限信息:" + user.getPerms());
        info.setRoles(user.getRoles());
        info.setStringPermissions(user.getPerms());
        return info;
    }

    //定义如何获取用户信息的业务逻辑,给shiro做登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
   
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        // Null username is invalid
        if (username == null) {
   
            throw new AccountException("请输入用户名");
        }
        User userDB = userService.findUserByName(username);
        if (userDB == null) {
   
            throw new UnknownAccountException("用户不存在");
        }
        //查询用户的角色和权限存到SimpleAuthenticationInfo中,这样在其它地方
        //SecurityUtils.getSubject().getPrincipal()就能拿出用户的所有信息,包括角色和权限
        Set<String> roles = roleService.getRolesByUserId(userDB.getUid());
        Set<String> perms = resourcesService.getResourcesByUserId(userDB.getUid());
        userDB.getRoles().addAll(roles);
        userDB.getPerms().addAll(perms);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDB, userDB.getPwd(), getName(
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值