天天看点

SpringBoot2的Shiro最简配置(两个文件)

目录

基础环境:依赖

Realm:认证鉴权器

WebSecurityManager:安全管理器

Test:登录测试

备注

基础环境:依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
           
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.4.0</version>
</dependency>
           

如果不是前后端分离,要实现页面级的权限控制,则加入以下依赖就可以使用shiro的权限标签了(记得在html头部加上相应约束:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="Thymeleaf" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
      >
           

):

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
           

Realm:认证鉴权器

package com.rz.monomer.modules.shiro;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rz.monomer.modules.user.entity.SysUserInfo;
import com.rz.monomer.modules.user.entity.SysUserRole;
import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
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 java.util.Set;
import java.util.stream.Collectors;

/**
 * 认证、鉴权类(必须)
 *
 * @author sunziwen
 * @version 1.0
 * @date 2019/11/14 14:06
 **/
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
    //以下三个服务是普通Dao查询,从数据库查询用户及其角色权限信息(这个类没有自动注入,需要在下个文件中手动注入)
    private SysUserInfoService userInfoService;
    private SysButtonInfoService buttonInfoService;
    private SysUserRoleService userRoleService;

    public ShiroRealm(SysUserInfoService userInfoService, SysButtonInfoService buttonInfoService, SysUserRoleService userRoleService) {
        this.userInfoService = userInfoService;
        this.buttonInfoService = buttonInfoService;
        this.userRoleService = userRoleService;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("check authorization info");

        SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();

        // 获取当前用户
        SysUserInfo userInfo = (SysUserInfo) principals.getPrimaryPrincipal();

        // 查询角色信息
        Set<Long> userRoles = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userInfo.getId()))
                                             .stream()
                                             .map(SysUserRole::getRoleId)
                                             .collect(Collectors.toSet());
        //角色所有权限
        Set<String> perms = buttonInfoService.getPermsByRoles(userRoles);
        authInfo.addStringPermissions(perms);
        return authInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        log.info("check authentication info");

        String username = (String) token.getPrincipal();

        // 获取用户信息
        SysUserInfo user = userInfoService.getOne(new LambdaQueryWrapper<SysUserInfo>().eq(SysUserInfo::getUsername, username));

        if (user == null) {
            return null;
        }

        /*SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
                ByteSource.Util.bytes(654321), getName());*/

        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        return authenticationInfo;
    }
}
           

WebSecurityManager:安全管理器

package com.rz.monomer.modules.shiro;

import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置类(必须)
 *
 * @author sunziwen
 * @version 1.0
 * @date 2019/11/14 14:08
 **/
@Configuration
@Slf4j
@AllArgsConstructor
public class WebSecurityManager {
    private SysUserInfoService userInfoService;
    private SysButtonInfoService buttonInfoService;
    private SysUserRoleService userRoleService;

    /**
     * 安全管理器
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        return securityManager;
    }

    /**
     * 认证鉴权器(安全管理器的依赖)
     */
    @Bean
    public ShiroRealm realm() {
        return new ShiroRealm(userInfoService, buttonInfoService, userRoleService);
    }

    /**
     * 配置拦截规则
     */
    @Bean
    public ShiroFilterFactoryBean filter(org.apache.shiro.mgt.SecurityManager securityManager) {
        log.info("config shiro filter");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 定义URL拦截链
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 允许匿名用户访问首页
        filterChainDefinitionMap.put("/shiro/index", "anon");
        // 定义注销路径
        filterChainDefinitionMap.put("/shiro/logout", "logout");
        // 所有用户界面都需要身份验证,否则会跳转到loginurl,由FormAuthenticationFilter处理
        filterChainDefinitionMap.put("/shiro/user/**", "authc");
        // 为login路径定义拦截,由FormAuthenticationFilter处理
        filterChainDefinitionMap.put("/shiro/login", "authc");
        // 所有vip路径要求具备vip角色权限
        filterChainDefinitionMap.put("/shiro/vip/**", "roles[vip]");
        // 指定loginurl 路径
        shiroFilterFactoryBean.setLoginUrl("/shiro/login");
        // 登录成功后跳转路径
        shiroFilterFactoryBean.setSuccessUrl("/shiro/user/");
        // for un authenticated
        shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/unauth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        // 自定义filters,可覆盖默认的Filter列表,参考 DefaultFilter
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();

        // 定制logout 过滤,指定注销后跳转到登录页(默认为根路径)
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl("/shiro/login");
        filters.put("logout", logoutFilter);

        // 定制authc 过滤,指定登录表单参数
        FormAuthenticationFilter authFilter = new FormAuthenticationFilter();
        authFilter.setUsernameParam("username");
        authFilter.setPasswordParam("password");
        filters.put("authc", authFilter);

        shiroFilterFactoryBean.setFilters(filters);
        return shiroFilterFactoryBean;
    }
}
           

Test:登录测试

package com.rz.monomer.modules.user.controller;

import com.rz.monomer.commons.utils.Md5Encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@RestController
@Slf4j
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(username, Md5Encrypt.md5(password));

        try {
            // 执行登录
            subject.login(token);

        } catch (UnknownAccountException e) {

            // 未知用户
            log.warn("the account {}  is not found", username);

            return "account not found";
        } catch (IncorrectCredentialsException e) {

            // 用户或密码不正确
            log.warn("the account or password is not correct");
            return "account or password not correct";

        }
        return "login success";
    }

}
           

备注

有问题加威型:sunziwen3366。备注CSDN

继续阅读