stoneechogx 2020-01-29
Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话管理解决方案。下面是在SpringBoot中使用Shiro进行认证和授权的例子,代码如下:
导入SpringBoot和Shiro依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.2</version> </dependency> </dependencies>
也可以直接导入Apache Shiro提供的starter:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> </dependency>
package 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; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //设置未认证(登录)时,访问需要认证的资源时跳转的页面 shiroFilterFactoryBean.setLoginUrl("/loginPage"); //设置访问无权限的资源时跳转的页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedPage"); //指定路径和过滤器的对应关系 Map<String, String> 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; } }
package 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<String, Object> 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<String, Object> getUserInfo(String username) { Map<String, Object> 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<String> getRoles(String username) { Set<String> roles = new HashSet<>(); roles.add("user"); roles.add("admin"); return roles; } }
package 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角色!"; } }