1. 程式人生 > >springboot 配置 shiro

springboot 配置 shiro

目錄

一、引入 shiro 的包

二、自定義 realm 

三、shiro 配置

四、寫一個 controller 測試

五、無許可權的時候直接報錯的錯誤方式


前提:

先準備一個 springboot+mybatis 的環境:https://blog.csdn.net/weidong_y/article/details/81709391

一、引入 shiro 的包

<!-- shiro 配置 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>

二、自定義 realm 

MyShiroRealm.java

package com.yyzheng.oa.shiro;

import com.yyzheng.oa.dao.User;
import com.yyzheng.oa.service.PermissionService;
import com.yyzheng.oa.service.RoleService;
import com.yyzheng.oa.service.UserService;
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.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

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

public class MyShiroRealm extends AuthorizingRealm {
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private UserService userService;

    // 角色許可權和對應許可權新增
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 獲取登入使用者名稱
        String userName = (String)principalCollection.getPrimaryPrincipal();
        // 查詢使用者的角色資訊
        Set<String> roles = getRolesByUsername(userName);
        // 查詢角色的許可權資訊
        Set<String> permissions = getPermissionsByUserName(userName);
        // 設定使用者的角色和許可權
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);

        return simpleAuthorizationInfo;
    }

    // 根據使用者名稱字從資料庫中獲取當前使用者的許可權資料
    private Set<String> getPermissionsByUserName(String userName) {
        List<String> list = permissionService.queryPermissionNameByUserName(userName);
        if( list != null ){
            Set<String> sets = new HashSet<>(list);
            return sets;
        }else{
            return null;
        }
    }

    // 根據使用者名稱字從資料庫中獲取當前使用者的角色資料
    private Set<String> getRolesByUsername(String userName) {
        List<String> list = roleService.queryRoleNameByUsername(userName);
        if( list != null ){
            Set<String> sets = new HashSet<>(list);
            return sets;
        }else{
            return null;
        }
    }

    // 認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1.從主體傳過來的資訊中獲取使用者名稱
        String userName = (String)authenticationToken.getPrincipal();
        // 2.通過使用者名稱到資料庫獲取憑證
        String password = getPasswordByUserName(userName);
        if( password == null ){
            return  null;
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,password,"myShiroRealm");
        return simpleAuthenticationInfo;
    }

    // 通過使用者名稱從資料庫中獲取當前使用者的密碼
    private String getPasswordByUserName(String userName) {
        User user = userService.queryUserByUserName(userName);
        if( user != null ){
            return user.getPassword();
        }else{
            return null;
        }
    }

}

三、shiro 配置

package com.yyzheng.oa.config;

import com.yyzheng.oa.exception.MyExceptionResolver;
import com.yyzheng.oa.shiro.MyShiroRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfiguration {

    // 建立自定義 realm
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }

    // 建立 SecurityManager 物件
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    // Filter工廠,設定對應的過濾條件和跳轉條件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        // 登出
        map.put("/logout", "logout");
        // 對所有使用者認證
        map.put("/**", "authc");
        // 對登入跳轉介面進行釋放
        map.put("/subLogin", "anon");
        map.put("/err", "anon");
        // 登入
        // 注意:這裡配置的 /login 是指到 @RequestMapping(value="/login")中的 /login
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 首頁
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 錯誤頁面,認證不通過跳轉
        shiroFilterFactoryBean.setUnauthorizedUrl("/err");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    // 加入註解的使用,不加這個,註解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    // 跟上面的註解配置搭配使用,有時候加了上面的配置後註解不生效,需要加入下面的配置
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
        app.setProxyTargetClass(true);
        return app;
    }

}

四、寫一個 controller 測試

@Controller
public class UserController {

    @RequestMapping(value = "/login")
    public String login(){
        return "/login";
    }

    @RequestMapping(value = "/err")
    public String err(){
        return "/err";
    }

    @RequestMapping(value = "/subLogin")
    public String subLogin(User user){
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
        try{
            subject.login(token);
        }catch (AuthenticationException e){
            e.printStackTrace();
            return e.getMessage();
        }
        return "success";
    }

    @RequiresRoles(value = "admin")
    @RequestMapping(value = "/test")
    @ResponseBody
    public String test(){
        return  "123";
    }
}

五、無許可權的時候直接報錯的錯誤方式

自定義一個異常攔截,自定義跳轉頁面。

MyExceptionResolver.java 攔截下異常。

package com.yyzheng.oa.exception;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

public class MyExceptionResolver implements HandlerExceptionResolver{

    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("==============異常開始=============");
        //如果是shiro無權操作,因為shiro 在操作auno等一部分不進行轉發至無許可權url
        if(ex instanceof UnauthorizedException){
            // 跳轉到 templates 檔案下面找 err.html 頁面
            ModelAndView mv = new ModelAndView("err");
            return mv;
        }
        ex.printStackTrace();
        ModelAndView mv = new ModelAndView("err");
        mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
        return mv;
    }
}

在shiro中配置一下:

// 自定義異常捕獲註冊
    @Bean
    public HandlerExceptionResolver solver(){
        HandlerExceptionResolver handlerExceptionResolver = new MyExceptionResolver();
        return handlerExceptionResolver;
    }