天天看點

[spring-boot] 內建shiroshiro介紹加入依賴ShiroConfig建立realm登入

shiro介紹

shiro是一個權限管理架構,基于使用者-角色-權限。一個使用者可以有多個角色,一個角色有多個權限,每個權限指定了資源的通路。

shiro的原理是在所有請求之前設定一個filter,這個filter判斷哪些資源需要權限,哪些不要,對于不需要權限的直接放行,對于需要權限的,使用securityManager和realm進行身份驗證和授權,如果驗證失敗或者權限不足,都跳轉到登入頁面或者傳回錯誤資訊。這和我們自己使用賬号密碼判斷是一樣的,隻是這個架構讓我們少寫很多代碼。

spring-boot 內建shiro其實相當簡單。

加入依賴

//shiro
compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'
           

ShiroConfig

建立一個配置檔案,用來配置shiro

package com.example.shiro;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * Shiro 配置
 */
@Configuration
public class ShiroConfig {
    //建立shiroFilterFactoryBean, 設定securityManager、配置filterChain
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean createShiroFilterFactoryBean() {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(createSecurityManager());
        bean.setLoginUrl("/admin/web/login"); //登入頁面

        Map<String, String> filterChainMap = new LinkedHashMap<>(); //這裡一定要是有序的
        //這裡可以從資料庫中讀取權限-資源規則
        filterChainMap.put("/api/v1/admin/login", "anon"); //登入不需要驗證權限
        filterChainMap.put("/api/v1/admin/**", "authc"); //其他api需要權限
        filterChainMap.put("/admin/web/login", "anon");//登入頁面不需要權限
        filterChainMap.put("/admin/web/**", "authc");//其他頁面需要權限
        bean.setFilterChainDefinitionMap(filterChainMap);
        return bean;
    }

    //建立一個securityManager
    @Bean(name = "securityManager")
    public SecurityManager createSecurityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager(new UserRealm());
        return manager;
    }
}
           

建立realm

realm 主要用來驗證密碼和授權

@Component
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Override
    public String getName() {
        return "user-realm";
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return true;
    }

    //擷取使用者的驗證資訊,用于和token進行對比
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        User user = userService.findUserByAccount(userName);
        if (user == null) {
            return null;
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }


    //給使用者設定角色資訊
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        User user = (User) principals.getPrimaryPrincipal();
        Set<String> roles=new HashSet<>();
        roles.add(user.getRole());
        return new SimpleAuthorizationInfo(roles);
    }

    //設定權限資訊
    @Override
    protected Collection<Permission> getPermissions(AuthorizationInfo info) {
        return super.getPermissions(info);
    }
}
           

登入

@PostMapping("/login")
    @ResponseBody
    public DtoWrap login(@RequestBody UserDto userDto) {
        DtoWrap result = new DtoWrap();
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(userDto.getUserName(), userDto.getPassword());
        try {
            subject.login(token);
            //if no exception, that's it, we're done!
        } catch (AuthenticationException ae) {
            throw new BusinessException("使用者名或密碼錯誤");
        }
        return result;
    }
           

繼續閱讀