本文共 8590 字,大约阅读时间需要 28 分钟。
慕课Shiro安全框架入门()在学习的时候,前三章还是不错的,第四章Spring集成Shiro内容老些过时了,推荐给大家一个博主的博客(),写的挺不错
虽然博主已经很详细的讲解了整合的内容,但我还是觉得有些地方不是很清楚对于新手,下面写一些自己的观点,如有错误,欢迎指正
我们先看一下自定义realm的代码
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 java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;public class CustomRealm extends AuthorizingRealm { MapuserMap = new HashMap (16); { //81dc9bdb52d04dc20036dbd8313ed055 userMap.put("Mark","f2d9ffba24994ac1cbeff23d94ddb62a"); super.setName("CustomRealm"); //Thread.currentThread().setName();为当前线程设置名称 } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); //模拟从数据库或缓存中获取角色数据 Set roles = getRolesByUsername(username); Set permissions = getPermissionsByUsername(username); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } private Set getPermissionsByUsername(String username) { Set set = new HashSet (); set.add("user:delete"); set.add("user:update"); return set; } private Set getRolesByUsername(String username) { Set set = new HashSet (); set.add("admin"); set.add("user"); return set; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //1、AuthenticationToken 主体传过来的认证信息中,获取用户名 String username = (String)token.getPrincipal(); //2、通过用户名到数据库中获取凭证 String password = getPasswordByUsername(username); if(password==null){ return null; } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo("Mark",password,"CustomRealm"); info.setCredentialsSalt(ByteSource.Util.bytes("Mark")); return info; } //模拟数据库查询凭证 private String getPasswordByUsername(String username) { return userMap.get(username); } public static void main(String[] args) { Md5Hash md5Hash = new Md5Hash("1234","Mark"); System.out.println(md5Hash.toString()); }}
以及测试类
import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.text.IniRealm;import org.apache.shiro.subject.Subject;import org.junit.Test;import realm.CustomRealm;public class CustomRealmTest { CustomRealm customRealm = new CustomRealm(); @Test public void TestIniRealm(){ //1.构建 securitymanager环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(customRealm); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("MD5"); matcher.setHashIterations(1); customRealm.setCredentialsMatcher(matcher); //2.主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("Mark","1234"); subject.login(token); System.out.println("isAuthenticated: "+subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); }}
接下来我们提出问题
一、在ShiroConfig,它是Shiro的配置文件,作为配置文件,它在授权和认证中扮演了什么角色呢?
我们看一下最基本的配置:ShiroConfig代码
我们发现Spring在整合Shiro时,有一个SecurityManager的bean在配置文件中
实际上,在上面的测试类中就已经把答案写出来了
在HomeIndexController被访问时,在从SecurityUtils里边创建一个 subject之前,spring会自动在上下文寻找securityManager的bean并注入到SecurityUtils中,因此配置文件只是在为原来将原来写在测试类中的各个组件拆分,将它们组装成spring的bean,并让它们在合适的上下文处注入
package com.cj.shirodemo.config;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.spring.LifecycleBeanPostProcessor;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.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import java.util.LinkedHashMap;import java.util.Map;/** * 描述: * * @author caojing * @create 2019-01-27-13:38 */@Configurationpublic class ShiroConfig { @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); MapfilterChainDefinitionMap = new LinkedHashMap<>(); // filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/front/**", "anon"); filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/user/**", "authc"); //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); defaultSecurityManager.setRealm(customRealm()); return defaultSecurityManager; } @Bean public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); return customRealm; }}
二、在CustomRealm,它是Shiro授权和认证的核心,那么它都起到了哪些作用?
如上,先上代码
最简单的CustomRealm,它继承自AuthorizingRealm复写了父类的两个方法,即授权和认证,实际上正是通过这两个方法的返回结果来达到安全认证目的
package com.cj.shirodemo.config;import org.apache.shiro.SecurityUtils;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.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import java.util.HashSet;import java.util.Set;/** * 描述: * * @author caojing * @create 2019-01-27-13:57 */public class CustomRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = (String) SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); SetstringSet = new HashSet<>(); stringSet.add("user:show"); stringSet.add("user:admin"); info.setStringPermissions(stringSet); return info; } /** * 这里可以注入userService,为了方便演示,我就写死了帐号了密码 * private UserService userService; * * 获取即将需要认证的信息 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("-------身份认证方法--------"); String userName = (String) authenticationToken.getPrincipal(); String userPwd = new String((char[]) authenticationToken.getCredentials()); //根据用户名从数据库获取密码 String password = "123"; if (userName == null) { throw new AccountException("用户名不正确"); } else if (!userPwd.equals(password )) { throw new AccountException("密码不正确"); } return new SimpleAuthenticationInfo(userName, password,getName()); }}
其余部分,博主已经总结很详细了,不再复述
转载地址:http://eoazi.baihongyu.com/