天天看點

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

繼續閱讀