龙空技术网

Srping boot集成Shiro实现用户身份认证与权限控制

智慧魔法豆浆 230

前言:

如今看官们对“apacheauthz模块”大体比较珍视,小伙伴们都想要学习一些“apacheauthz模块”的相关资讯。那么小编在网摘上网罗了一些对于“apacheauthz模块””的相关文章,希望同学们能喜欢,各位老铁们快快来了解一下吧!

通过Shiro实现用户登录验证,授权,对不同用户角色访问资源进行验证,对用户权限访问资源验证,通过迭代加密方式提高用户密码的安全性,本文通过gradle进行构建

引入依赖

compile group: 'org.apache.shiro',name: 'shiro-spring-boot-web-starter',version: '1.4.0'compile group: 'org.apache.shiro',name: 'shiro-ehcache',version: '1.3.2'
添加shiro 配置
package com.language.shiro;import com.language.filter.TokenCheckFilter;import org.apache.shiro.authc.credential.CredentialsMatcher;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.cache.MemoryConstrainedCacheManager;import org.apache.shiro.cache.ehcache.EhCacheManager;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.codec.Base64;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.CookieRememberMeManager;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.apache.shiro.session.mgt.SessionManager;import org.apache.shiro.web.servlet.SimpleCookie;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Qualifier;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;import javax.servlet.Filter;/** * @author ljj * @Date 2019/2/24 19:35 */@Configuration@SuppressWarnings("ALL")public class ShiroConfig {    /**     * 自定义验证     * @return     */    @SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")    @Bean    ShiroRealm ShiroRealm() {        ShiroRealm shiroRealm = new ShiroRealm();        shiroRealm.setCredentialsMatcher(retryLimitCredentialsMatcher());        return shiroRealm;    }//    /**//     *密码加密//     * @return//     *///    @Bean//    HashedCredentialsMatcher hashedCredentialsMatcher(){//        HashedCredentialsMatcher hashedCredentialsMatcher =new HashedCredentialsMatcher();//        //加密方式//        hashedCredentialsMatcher.setHashAlgorithmName("SHA1");//        //加密次数//        hashedCredentialsMatcher.setHashIterations(1024);//        return hashedCredentialsMatcher;//    }    /**     * 缓存管理器     * @return cacheManager     */    @Bean    public EhCacheManager ehCacheManager(){        EhCacheManager cacheManager = new EhCacheManager();        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");        return cacheManager;    }    /**     * 限制登录次数(密码加密方式)     * @return 匹配器     */    @Bean    public CredentialsMatcher retryLimitCredentialsMatcher() {        RetryLimitCredentialsMatcher retryLimitCredentialsMatcher = new RetryLimitCredentialsMatcher(ehCacheManager());        retryLimitCredentialsMatcher.setHashAlgorithmName("SHA1");        retryLimitCredentialsMatcher.setHashIterations(1024);        // 设置限制        retryLimitCredentialsMatcher.setMaxRetryNum(5);        return retryLimitCredentialsMatcher;    }    /**     * 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;    }    /**     * 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;    }    @Bean    DefaultWebSecurityManager securityManager() {        DefaultWebSecurityManager sm = new DefaultWebSecurityManager();        sm.setRealm(ShiroRealm());        sm.setCacheManager(ehCacheManager());        //注入记住我管理器        sm.setRememberMeManager(rememberMeManager());        //注入自定义sessionManager        sm.setSessionManager(sessionManager());        return sm;    }    /**    *自定义sessionManager     */    @Bean    SessionManager sessionManager() {        return new MySessionManager();    }    @Bean    ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager) {        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();        shiroFilter.setSecurityManager(securityManager);        //SecurityUtils.setSecurityManager(securityManager);        Map<String, String> filterMap = new LinkedHashMap<>();        //配置不会被拦截的链接,顺序判断        // 配置不会被拦截的链接 顺序判断        filterMap.put("/login", "anon");        filterMap.put("/logout", "anon");        //authc:所有url必须通过认证才能访问,anon:所有url都可以匿名访问        filterMap.put("/**", "authc");        shiroFilter.setFilterChainDefinitionMap(filterMap);        //自定义过滤器        Map<String, Filter> filterChainDefinitionMap = new LinkedHashMap<>();        filterChainDefinitionMap.put("authc", new TokenCheckFilter());        shiroFilter.setFilters(filterChainDefinitionMap);        return shiroFilter;    }    /**     * Shiro生命周期处理器 * @return     */    @Bean    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {        return new LifecycleBeanPostProcessor();    }    /**     * setUsePrefix(true)用于解决一个奇怪的bug。在引入spring aop的情况下。     * 在@Controller注解的类的方法中加入@RequiresRole等shiro注解,会导致该方法无法映射请求,导致返回404。     * 加入这项配置能解决这个bug     */    @Bean    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();        defaultAdvisorAutoProxyCreator.setUsePrefix(true);        return defaultAdvisorAutoProxyCreator;    }    /**     * 开启Shiro注解模式,可以在Controller中的方法上添加注解     * @param securityManager     * @return     */    @Bean    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultSecurityManager securityManager) {        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);        return authorizationAttributeSourceAdvisor;    }}
重写 DefaultWebSessionManager实现自定义过滤器
package com.language.shiro;import org.apache.shiro.web.servlet.ShiroHttpServletRequest;import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;import org.apache.shiro.web.util.WebUtils;import org.springframework.util.StringUtils;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import java.io.Serializable;/** * 重写 DefaultWebSessionManager * @Author Administrator * @create 2020/3/18 9:01 */public class MySessionManager extends DefaultWebSessionManager {    private static final String AUTHORIZATION = "authorization";    private static final String REFERENCED_SESSION_ID_SOURCE = "cookie";    public MySessionManager() {        super();        setGlobalSessionTimeout(DEFAULT_GLOBAL_SESSION_TIMEOUT * 1);    }    @Override    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {        String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);        //如果请求头中有 Authorization 则其值为sessionId        if (!StringUtils.isEmpty(id)) {            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);            return id;        } else {            //否则按默认规则从cookie取sessionId            return super.getSessionId(request, response);        }    }}
重写HashedCredentialsMatcher实现用户(登录次数、过期时间)管理
package com.language.shiro;import com.language.utils.JsonResult;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.ExcessiveAttemptsException;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.ehcache.EhCacheManager;import java.util.concurrent.atomic.AtomicInteger;/** * @Author Administrator * @create 2020/8/20 17:19 */public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {    private int maxRetryNum = 5;    //默认一个小时    private int lockTime = 60;    private EhCacheManager shiroEhcacheManager;    public void setMaxRetryNum(int maxRetryNum) {        this.maxRetryNum = maxRetryNum;    }    public RetryLimitCredentialsMatcher(EhCacheManager shiroEhcacheManager) {        this.shiroEhcacheManager = shiroEhcacheManager;    }    @Override    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {        Cache<String, AtomicInteger> passwordRetryCache = shiroEhcacheManager.getCache("passwordRetryCache");        String username = (String) token.getPrincipal();        //次数+ 1        AtomicInteger retryCount = passwordRetryCache.get(username);        if (null == retryCount) {            retryCount = new AtomicInteger(0);            passwordRetryCache.put(username, retryCount);        }        if (retryCount.incrementAndGet() > maxRetryNum) {//            throw new ExcessiveAttemptsException();            throw new ExcessiveAttemptsException("用户: " + username + ",认证失败超过"+maxRetryNum+"次,锁定时间:"+lockTime+"分钟");        }        boolean matches = super.doCredentialsMatch(token, info);        if (matches) {            //验证成功清除缓存时间            passwordRetryCache.remove(username);        }        return matches;    }}
添加自定义Realm 验证
package com.language.shiro;import com.language.entity.Menu;import com.language.entity.Role;import com.language.entity.User;import com.language.service.UserService;import com.language.utils.JsonResult;import com.language.utils.ServerResponseEnum;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.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Lazy;import org.springframework.util.StringUtils;import java.util.ArrayList;import java.util.List;import java.util.Set;/** *实现AuthorizingRealm接口用户用户认证 * @author ljj * @Date 2019/2/24 20:38 */    public class ShiroRealm extends AuthorizingRealm {    /**     * 用户认证登录     */    @Lazy    @Autowired    private UserService userService;    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        //将token转换成UsernamePasswordToken        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;        // 获取用户名即可        String loginName = upToken.getUsername();        // 获取密码        String password = upToken.getPassword().toString();        upToken.isRememberMe();        if(StringUtils.isEmpty(loginName)){            throw new IncorrectCredentialsException("用户名不能为空");        }else if(StringUtils.isEmpty(password)){            throw new IncorrectCredentialsException("密码不能为空");        }        //根据账户名称查询用户信息        User user = userService.getByLoginName(loginName);        if(user == null){            throw new UnknownAccountException();        }        if(user.getPassword().equals(password)){            throw new IncorrectCredentialsException();        }        if(user.getLoginFlag().equals("0")){            throw new LockedAccountException();        }        //取出盐并编码        ByteSource salt = ByteSource.Util.bytes(user.getLoginName());        return new SimpleAuthenticationInfo(user, user.getPassword(),salt, getName());    }    //用于授权角色权限和对应权限添加    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        // 需要把角色和权限放入info中        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        // 获取User用户        User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next();        List<String> permissionList = new ArrayList<>();        List<String> roleNameList = new ArrayList<>();        //获取角色信息        List<Role> roleSet = user.getRoles();        if (roleSet != null) {            for (Role role : roleSet) {                roleNameList.add(role.getName());                List<Menu> menuSet = role.getMenus();                if (menuSet != null) {                    for (Menu menu : menuSet) {                        permissionList.add(menu.getName());                    }                }            }        }        // 权限设定        authorizationInfo.addStringPermissions(permissionList);        // 角色设定        authorizationInfo.addRoles(roleNameList);        return authorizationInfo;    }}
controller层实现
package com.language.controller;import com.language.entity.Role;import com.language.entity.User;import com.language.service.UserService;import com.language.utils.JsonResult;import com.language.utils.ServerResponseEnum;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;/** * 登录 * @author Administrator */@RestController@RequestMapping("")public class LoginController {    @Autowired    private UserService userService;    JsonResult jsonresult =new JsonResult();    @PostMapping("/login")    public JsonResult login(@RequestBody User user) {        /**         * 使用Shrio编写认证操作         */        Subject subject = SecurityUtils.getSubject();        UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginName(), user.getPassword());        // 登录验证        try {            subject.login(token);            String sessionId = (String) subject.getSession().getId();            jsonresult.setMsg("登录成功");            jsonresult.setToken(sessionId);            return jsonresult;        } catch (UnknownAccountException e) {            return JsonResult.error(ServerResponseEnum.ACCOUNT_NOT_EXIST);        } catch (IncorrectCredentialsException e) {            return JsonResult.error(ServerResponseEnum.INCORRECT_CREDENTIALS);        } catch (LockedAccountException e) {            return JsonResult.error(ServerResponseEnum.ACCOUNT_IS_DISABLED);        } catch (ExcessiveAttemptsException e) {            return JsonResult.error(1005,e.getMessage());        } catch (Throwable e) {            e.printStackTrace();            return JsonResult.error(ServerResponseEnum.ERROR);        }    }    /**     * 登出     */    @PostMapping("/logout")    public JsonResult logout() {        Subject subject = SecurityUtils.getSubject();        subject.logout();        jsonresult.setMsg("安全退出");        return jsonresult;    }}
dao层实现
package com.language.dao;import com.github.pagehelper.Page;import com.language.common.BaseDao;import com.language.entity.Menu;import com.language.entity.Role;import com.language.entity.User;import org.springframework.stereotype.Repository;import java.util.List;import java.util.Map;/** * 用户Dao接口 * @author Administrator */@Repositorypublic interface UserDao extends BaseDao<User> {  /** * 根据登录名称查询用户(用于登录) * @param loginName * @return */public User getByLoginName(String loginName);}
Service层实现
package com.language.service;import com.github.pagehelper.Page;import com.language.common.BaseService;import com.language.entity.User;import com.language.utils.JsonResult;import java.util.List;/** * @author Administrator */public interface UserService extends BaseService<User> {    /**     * 根据登录名称查询用户(用于登录)     * @param loginName     * @return     */    public User getByLoginName(String loginName);}

标签: #apacheauthz模块