Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话管理解决方案。下面是在SpringBoot中使用Shiro进行认证和授权的例子,代码如下:
pom.xml
导入SpringBoot和Shiro依赖:
Copyorg.springframework.boot spring-boot-starter-web org.apache.shiro shiro-spring 1.4.2
也可以直接导入Apache Shiro提供的starter:
Copyorg.apache.shiro shiro-spring-boot-web-starter
Shiro配置类
Copypackage com.cf.shiro1.config;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.realm.Realm;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.HashMap;import java.util.Map;@Configurationpublic class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //设置未认证(登录)时,访问需要认证的资源时跳转的页面 shiroFilterFactoryBean.setLoginUrl("/loginPage"); //设置访问无权限的资源时跳转的页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedPage"); //指定路径和过滤器的对应关系 Map filterMap = new HashMap<>(); //设置/user/login不需要登录就能访问 filterMap.put("/user/login", "anon"); //设置/user/list需要登录用户拥有角色user时才能访问 filterMap.put("/user/list", "roles[user]"); //其他路径则需要登录才能访问 filterMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") Realm realm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(realm); return defaultWebSecurityManager; } @Bean public Realm realm() { MyRealm realm = new MyRealm(); //使用HashedCredentialsMatcher带加密的匹配器来替换原先明文密码匹配器 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //指定加密算法 hashedCredentialsMatcher.setHashAlgorithmName("MD5"); //指定加密次数 hashedCredentialsMatcher.setHashIterations(3); realm.setCredentialsMatcher(hashedCredentialsMatcher); return realm; }}
自定义Realm
Copypackage com.cf.shiro1.config;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.crypto.hash.SimpleHash;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 MyRealm extends AuthorizingRealm { /** * 授权 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { Object username = principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setRoles(getRoles(username.toString())); return simpleAuthorizationInfo; } /** * 认证 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); Map userInfo = getUserInfo(username); if (userInfo == null) { throw new UnknownAccountException(); } //盐值,此处使用用户名作为盐 ByteSource salt = ByteSource.Util.bytes(username); SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, userInfo.get("password"), salt, getName()); return authenticationInfo; } /** * 模拟数据库查询,通过用户名获取用户信息 * * @param username * @return */ private Map getUserInfo(String username) { Map userInfo = null; if ("zhangsan".equals(username)) { userInfo = new HashMap<>(); userInfo.put("username", "zhangsan"); //加密算法,原密码,盐值,加密次数 userInfo.put("password", new SimpleHash("MD5", "123456", username, 3)); } return userInfo; } /** * 模拟查询数据库,获取用户角色列表 * * @param username * @return */ private Set getRoles(String username) { Set roles = new HashSet<>(); roles.add("user"); roles.add("admin"); return roles; }}
Controller
Copypackage com.cf.shiro1.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.subject.Subject;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/user")public class UserController { /** * 登录 * @param username * @param password * @return */ @RequestMapping("/login") public String userLogin(String username, String password) { String result; //获取当前用户 Subject currentUser = SecurityUtils.getSubject(); //用户是否已经登录,未登录则进行登录 if (!currentUser.isAuthenticated()) { //封装用户输入的用户名和密码 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); try { //登录,进行密码比对,登录失败时将会抛出对应异常 currentUser.login(usernamePasswordToken); result = "登录成功"; } catch (UnknownAccountException uae) { result = "用户名不存在"; } catch (IncorrectCredentialsException ice) { result = "密码错误"; } catch (LockedAccountException lae) { result = "用户状态异常"; } catch (AuthenticationException ae) { result = "登录失败,请与管理员联系"; } } else { result = "您已经登录成功了"; } return result; } @RequestMapping("/list") public String userList() { return "访问我需要登录并且需要拥有user角色!"; }}