首页 > 学院 > 开发设计 > 正文

spring boot集成shiro

2019-11-08 03:01:07
字体:
来源:转载
供稿:网友

添加shiro依赖

<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-sPRing</artifactId> <version>1.3.2</version></dependency>

编写shiro configuration文件ShiroConfig.java

package com.ls.shiro;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;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.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.apache.shiro.mgt.SecurityManager;import java.util.LinkedHashMap;import java.util.Map;/** * <p></p> * Created by zhezhiyong@163.com on 2017/2/17. */@Configurationpublic class ShiroConfig { /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * <p> * Filter Chain定义说明 * 1、一个URL可以配置多个Filter,使用逗号分隔 * 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles */ @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/logout", "logout"); //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); return securityManager; } /** * 身份认证realm; * (这个需要自己写,账号密码校验;权限等) */ @Bean public ShiroRealm shiroRealm() { ShiroRealm shiroRealm = new ShiroRealm(); shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return shiroRealm; } /** * 凭证匹配器 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 * 所以我们需要修改下doGetAuthenticationInfo中的代码; * ) */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5("")); hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);//默认true return hashedCredentialsMatcher; } /** * 开启shiro aop注解支持. * 使用代理方式;所以需要开启代码支持; */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; }}

编写自定义RealmShiroRealm.java

package com.ls.shiro;import com.github.pagehelper.util.StringUtil;import com.ls.model.Permission;import com.ls.model.Role;import com.ls.model.User;import com.ls.service.PermissionService;import com.ls.service.RoleService;import com.ls.service.UserService;import com.ls.util.StringUtils;import org.apache.shiro.SecurityUtils;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.AuthorizationException;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.ByteSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.annotation.Resource;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;import static freemarker.ext.servlet.FreemarkerServlet.KEY_SESSION;/** * <p></p> * Created by zhezhiyong@163.com on 2017/2/17. */public class ShiroRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(getClass()); @Resource private UserService userService; @Resource private RoleService roleService; @Resource private PermissionService permissionService; /** * 登录验证 * * @param token 是用来验证用户身份 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { logger.debug("登录验证"); //获取用户的输入的账号. String loginName = String.valueOf(token.getPrincipal()); String passWord = new String((char[]) token.getCredentials()); if (StringUtils.isEmpty(loginName)) { throw new AuthenticationException("用户名或密码错误."); } //通过username从数据库中查找 User对象,如果找到,没找到. //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 User user = userService.findByLoginName(loginName); if (user == null) { return null; } this.setSession(KEY_SESSION, user); /* * 获取权限信息:这里没有进行实现, * 请自行根据UserInfo,Role,Permission进行实现; * 获取之后可以在前端for循环显示所有链接; */ //userInfo.setPermissions(userService.findPermissions(user)); //账号判断; //加密方式; //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user.getLoginName(), //用户名 user.getPassword(), //密码 ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt getName() //realm name ); //明文: 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验// SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(// user.getLoginName(), //用户名// user.getPassword(), //密码// getName() //realm name// ); return authenticationInfo; } /** * 此方法调用 hasRole,haspermission的时候才会进行回调. * <p> * 权限信息.(授权): * 1、如果用户正常退出,缓存自动清空; * 2、如果用户非正常退出,缓存自动清空; * 3、如果我们修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。 * (需要手动编程进行实现;放在service进行调用) * 在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例, * 调用clearCached方法; * :Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { /* * 当没有使用缓存的时候,不断刷新页面的话,这个代码会不断执行, * 当其实没有必要每次都重新设置权限信息,所以我们需要放到缓存中进行管理; * 当放到缓存中时,这样的话,doGetAuthorizationInfo就只会执行一次了, * 缓存过期之后会再次执行。 */ logger.debug("shiro 授权"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); // 获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next() // String currentUsername = // (String)super.getAvailablePrincipal(principals); String loginName = String.valueOf(principals.getPrimaryPrincipal()); if (StringUtil.isEmpty(loginName)) { throw new AuthorizationException(); } final User user = userService.findByLoginName(loginName); final Role role = roleService.findByUserId(user.getId()); List<Permission> permissionList = permissionService.findByRoleId(role.getId()); authorizationInfo.addRole(role.getRole()); List<String> pList = permissionList.stream().map(Permission::getPermission).collect(Collectors.toList()); authorizationInfo.addStringPermissions(pList);// for (Role role : roles) {// // 添加角色// authorizationInfo.addRole(role.getSign());// final List<Permission> permissions = permissionService.getPermissionsByRoleId(role.getId());// for (Permission permission : permissions) {// // 添加权限// authorizationInfo.addStringPermission(permission.getSign());// }// } return authorizationInfo; } /** * 将一些数据放到ShiroSession中,以便于其它地方使用 * <p> * 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到 */ private void setSession(Object key, Object value) { Subject currentUser = SecurityUtils.getSubject(); if (null != currentUser) { Session session = currentUser.getSession(); logger.debug("Session默认超时时间为[" + session.getTimeout() + "]毫秒"); session.setAttribute(key, value); } }}

shiro密码加密

package com.ls.util;import org.apache.shiro.crypto.hash.SimpleHash;import org.apache.shiro.util.ByteSource;/** * <p></p> * Created by zhezhiyong@163.com on 2017/2/18. */public class CommonUtils { /** * 获取shiro加密,进行MD5 2次加密 * @param password * @param salt * @return */ public static String getEncryptPsw(String password, String salt) { return new SimpleHash("md5", password, ByteSource.Util.bytes(salt), 2).toHex(); }}

使用shiro权限

如果没有权限,会报异常org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:view]

在控制器上添加注释@RequiresPermissions("user:view")

osc源码地址

osc源码地址,如果你觉得对你有帮助请star,谢谢


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表