當我們開發一個springboot項目,建議
登陸控制和權限控制,不要自己手動寫代碼驗證和攔截器寫安全攔截,
可以統一使用shiro框架
先添加依賴
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
一共需要新建兩個文件
- ShiroConfig
import java.util.LinkedHashMap;
import java.util.Map;
import com.hjr.shiro.MyShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
/**
* 憑證匹配器
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//md5加密1次
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(1);
return hashedCredentialsMatcher;
}
/**
* 自定義realm
*
* @return
*/
@Bean
public MyShiroRealm userRealm() {
MyShiroRealm userRealm = new MyShiroRealm();
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return userRealm;
}
/**
* 核心的安全事務管理器
* @return
*/
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager ();
//設置realm
securityManager.setRealm(userRealm());
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* cookie管理對象;
* rememberMeManager()方法是生成rememberMe管理器,而且要將這個rememberMe管理器設置到securityManager中
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
//System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
return cookieRememberMeManager;
}
/**
* cookie對象;
* rememberMeCookie()方法是設置Cookie的生成模版,比如cookie的name,cookie的有效時間等等。
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
//System.out.println("ShiroConfiguration.rememberMeCookie()");
//這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 記住我cookie生效時間30天 ,單位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* 設置過濾規則
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必須設置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// setLoginUrl 如果不設置值,默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 或 "/login" 映射
shiroFilterFactoryBean.setLoginUrl("/notLogin");
// 設置無權限時跳轉的 url;
shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
// 設置攔截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//遊客,開發權限
filterChainDefinitionMap.put("/guest/**", "anon");
//用戶,需要角色權限 “user”
filterChainDefinitionMap.put("/user/**", "roles[user]");
//管理員,需要角色權限 “admin”
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//開放登陸接口
filterChainDefinitionMap.put("/login", "anon");
//其餘接口一律攔截
//主要這行代碼必須放在所有權限設置的最後,不然會導致所有 url 都被攔截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
System.out.println("Shiro攔截器工廠類注入成功");
return shiroFilterFactoryBean;
}
}
- MyShiroRealm
import com.hjr.admin.system.resource.mapper.ResourceMapper;
import com.hjr.admin.system.user.mapper.UserMapper;
import com.hjr.admin.system.user.model.UserModel;
import org.apache.shiro.authc.*;
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 org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MyShiroRealm extends AuthorizingRealm {
private static final Logger LOGGER = LoggerFactory.getLogger(UserModel.class);
protected static UserMapper userMapper = new UserMapper() ;
protected static ResourceMapper resourceMapper = new ResourceMapper() ;
/**
* 權限授權
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
UserModel sysUser = (UserModel) principals.getPrimaryPrincipal();
List<String> sysPermissions = resourceMapper.queryForListByChaId(sysUser.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(sysPermissions);
LOGGER.info("=====================================================================doGetAuthorizationInfo");
return info;
}
/**
* 登錄認證
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
UserModel userModel = new UserModel();
String password = "123456";
String hashAlgorithmName = "MD5";
String credentials = "123456";
int hashIterations = 1;
Object obj = new SimpleHash(hashAlgorithmName, credentials, "yanzhi", hashIterations);
System.out.println(obj);
userModel.setPassword(String.valueOf(obj));
// if (sysUser == null) {
// return null;
// }
LOGGER.info("===============================================================222222222222222222222");
}
shiro的功能分爲登錄認證與權限檢測,權限檢測只有在登錄認證成功之後纔有效。否則你所有的請求都會被跳轉到 shiroFilterFactoryBean.setLoginUrl("/notLogin");
登錄認證,需要先寫一個接口並訪問,參數爲username和password
// 從SecurityUtils裏邊創建一個 subject
Subject subject = SecurityUtils.getSubject();
// 在認證提交前準備 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 執行認證登陸
subject.login(token);
//根據權限,指定返回數據
String role = userMapper.getRole(username);
if ("user".equals(role)) {
return resultMap.success().message("歡迎登陸");
}
if ("admin".equals(role)) {
return resultMap.success().message("歡迎來到管理員頁面");
}
return resultMap.fail().message("權限錯誤!");
在登錄成功後纔可以進行權限驗證
重點
- 一共需要新建兩個文件
- 權限檢測只有在登錄認證成功之後纔有效,需要先寫一個接口並訪問,參數爲username和password,登陸成功後才能測試權限檢測功能