springboot整合shiro

springboot + shiro + easyui 搭建后台项目

目录

springboot + shiro + easyui 搭建后台项目

(一):shiro配置自定义Realm

realm的概念

自定义realm

(二):配置MD5加密

认证匹配器

MD5工具类

(三):shiroFilter的配置

(四):自定义表单认证

(五):登出处理

(六):shiro表的设计


(一):shiro配置自定义Realm

realm的概念

Realm是shiro中配置的数据源,用来表明处理用户认证和授权的逻辑,可以配置数据库来进行认证,授权操作,这里我们自定义自己的realm并使用MD5对数据进行加密来进行认证的操作

自定义realm

``

public class CustomRealm extends AuthorizingRealm {
​
    @Autowired
    UserService service ;
​
    @Autowired
    RoleService roleService ;
​
    @Autowired
    PermissionService permissionService ;
​
    @Autowired
    MenuService menuService ;
​
    @Autowired
    TreeService treeService ;
    
    //授权的方法,当controller需要有权限访问时,就会调用,如果配置了cache就只会调用一次,注意如果配置了缓存那么需要在更改权限的时候,同时清楚掉缓存
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //在认证方法中,如果返回值的第一个参数是用user填充的那么就返回这个user,如果是username,那么就返回username
        User user = (User) principalCollection.getPrimaryPrincipal() ;
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo() ;
        String username = user.getUsername() ;
        //通过用户名查询角色信息
        List<Role> roles = roleService.getRolesByUserName(username) ;
        for(Role role:roles){
            simpleAuthorizationInfo.addRole(role.getRoleName()) ;
            //通过角色去获取权限信息
            for(Permission permission :  permissionService.getPermissionByRoleId(role.getId() )){
                simpleAuthorizationInfo.addStringPermission(permission.getPermisson());
            }
        }
        return simpleAuthorizationInfo;
    }
​
    //认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登陆的用户名
        String loginName = (String) authenticationToken.getPrincipal();
        User user = service.getUserByName(loginName);
        //异常处理
        if(user == null){
            throw new UnknownAccountException() ;
        }
        if("I".equals(user.getStatus())){
            throw new LockedAccountException() ;
        }
        Session session =  SecurityUtils.getSubject().getSession() ;
        //将user放入session中
        SecurityUtils.getSubject().getSession().setAttribute("user",user );
        //把tree 加载到session中
        List<Role> roles1 = roleService.getRolesByUserName(user.getUsername()) ;
        List<Menu> menuslist = new ArrayList<>() ;
        for (Role role:roles1){
            List<Menu> menus =  menuService.getMenusByRoleId(role.getId()) ;
            menuslist.addAll(menus) ;
        }
        List<EasyuiTreeNode> easyuiTreeNodes = treeService.getTreeNodesByMenus(menuslist) ;
        ObjectMapper mapper = new ObjectMapper() ;
        String json = null ;
        try {
            //将list转换成json格式,easyui树需要的数据格式
            json = mapper.writeValueAsString(easyuiTreeNodes) ;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        session.setAttribute("tree",json );
        System.out.println("-------------" + easyuiTreeNodes);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),this.getSalt(user.getSalt()),getName() );
        return authenticationInfo;
    }
​
    
    private ByteSource getSalt(String salt){
       return ByteSource.Util.bytes(salt) ;
    }
}

 

(二):配置MD5加密

在shiro中我们可以配置认证的来源,比如数据库,ini文件等等,这里我们从数据库中进行认证,shiro认证的原理大致是,用户输入用户名和密码,然后通过我们配置的认证处理类(HashedCredentialsMatcher),来判断如何认证,这里我们会配置一个HashedCredentialsMatcher类,设置算法的名字'MD5',hash迭代的次数就是加盐之后在加盐(不知道是不是),设置编码(这个有点坑最好选择true),因为shiro的认证方法中会去判断如果不是true,就会用base64编码,最后可能会造成密码匹配不上。

认证匹配器

``

@Bean
public HashedCredentialsMatcher credentialsMatcher(){
    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher() ;
    //算法名字,其实可以随便填
    credentialsMatcher.setHashAlgorithmName("MD5");
    //迭代次数
    credentialsMatcher.setHashIterations(2);
    //编码的设置
    credentialsMatcher.setStoredCredentialsHexEncoded(true);
    return credentialsMatcher ;
}

MD5工具类

这里给大家分享一个MD5工具类(shiro自带的)

``

/**
 * shiro工具类
 *
 * @author dafei, Chill Zhuang
 */
public class ShiroKit {
​
    private static final String NAMES_DELIMETER = ",";
​
    /**
     * 加盐参数
     */
    public final static String hashAlgorithmName = "MD5";
​
    /**
     * 循环次数
     */
    public final static int hashIterations = 2;
​
    /**
     * shiro密码加密工具类
     *
     * @param credentials 密码
     * @param saltSource  密码盐
     * @return
     */
    public static String md5(String credentials, String saltSource) {
        ByteSource salt = ByteSource.Util.bytes(saltSource);
        return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations).toString();
    }
​
    /**
     * 获取随机盐值
     *
     * @param
     * @return
     */
    public static String getRandomSalt(String username) {
        String uuid = UUID.randomUUID().toString().replace("-", "") ;
        return username + uuid ;
    }
}

大家要测试的话可以分享一个列子

``

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShirodemoApplicationTests {
​
    @Test
    public void contextLoads() {
        String salt = ShiroKit.getRandomSalt( "tom") ;
        System.out.println("盐值======" + salt );
        String password = ShiroKit.md5("123456",salt ) ;
        System.out.println("密码======" + password);
        System.out.println("============" + ByteSource.Util.bytes("admin3b41d727b0af4164a9454f6805ac36b9")) ;
    }
}

(三):shiroFilter的配置

springboot整合shiro最重要的一部分也就是shirofilter的配置,这列贴一份自己demo的列子,大家可以作为参考,有认为不对的地方,可以指出来

``

@Configuration
public class ShiroConfig{
    
    //对shirofilter进行代理,说句实话 不太懂,没有配也跑起来了    懂得可以说下
     @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); 
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*"); 
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
        return filterRegistration;
    }
    
    //配置shirofilter,主要配置自定义过滤器链,以及登陆地址,等,注意的地方是,authc配置在最后,不然有可能导致anon的过滤器失效
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shirofilter(SecurityManager manager){
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean() ;
        //配置安全管理器
        shiroFilterFactoryBean.setSecurityManager(manager);
        //登陆controller的mapper 地址
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        //未认证的地址
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth.jsp");
        //登陆后跳转到指定地址
        Map<String,Filter> filtersMap = new LinkedHashMap<>() ;
        filtersMap.put("authc", new MyFormAuthenticationFilter()) ;
        shiroFilterFactoryBean.setFilters(filtersMap);
        Map<String,String> map = new LinkedHashMap<>() ;
        map.put("unauth.jsp","anon") ;
        map.put("/common/**", "anon") ;
        map.put("/easyui/**", "anon") ;
        map.put("/css/**", "anon");
        map.put("/images/**", "anon");
        map.put("/hello", "anon") ;
        map.put("/login","anon" ) ;
        map.put("/logout", "logout") ;
        map.put("/**", "authc") ;
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean ;
    }
​
    //自定义表单过滤器,主要是为了,在认证成功之后,跳转到指定的url中,因为shiro默认得到是会自动跳转到你之前输入的url中,所以配置表单过滤器,清楚session中的内容,跳转到指定url张
    @Bean
    public MyFormAuthenticationFilter customFormAuthenticationFilter(){
        System.out.println("ShiroConfiguration.formAuthenticationFilter()");
        MyFormAuthenticationFilter customFormAuthenticationFilter = new MyFormAuthenticationFilter();
        return customFormAuthenticationFilter;
    }
​
    //配置表单过滤器时,碰到一个问题,就是这个过滤器和filterchain时同级的,然后他是用authc指定的,所以导致了无法访问anon的url,导致无法导入静态资源
    @Bean
    public FilterRegistrationBean shiroFilterRegistration(MyFormAuthenticationFilter myFormAuthenticationFilter) {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(myFormAuthenticationFilter);
        filterRegistration.setEnabled(false);
        return filterRegistration;
    }
​
    //配置shiro安全过滤器,用来维护shiro的session管理,以及缓存管理,还有自定义的realm
    @Bean
    public SecurityManager securityManager(Realm realm,EhCacheManager ehCacheManager,SessionManager sessionManager){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager() ;
        defaultWebSecurityManager.setRealm(realm);
        defaultWebSecurityManager.setCacheManager(ehCacheManager);
        defaultWebSecurityManager.setSessionManager(sessionManager);
        return defaultWebSecurityManager ;
    }
​
    //自定义realm
    @Bean
    public CustomRealm customRealm(HashedCredentialsMatcher credentialsMatcher){
        CustomRealm customRealm  = new CustomRealm() ;
        customRealm.setCredentialsMatcher(credentialsMatcher);
        customRealm.setCachingEnabled(false); ;
        return customRealm ;
    }
​
    //认证匹配器
    @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher() ;
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(2);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher ;
    }
    //    权限配置(注解方式)
    /**
     * 下面的代码是添加注解支持,支持注解方式的权限配置
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib,防止重复代理和可能引起代理出错的问题
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor() ;
        return  lifecycleBeanPostProcessor ;
    }
​
    /**
     * 开启shiro权限注解功能
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
​
    /**
     * 缓存管理
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager(){
        return new EhCacheManager() ;
    }
​
    /**
     * session id
     * @return
     */
    @Bean
    public JavaUuidSessionIdGenerator javaUuidSessionIdGenerator(){
        return  new JavaUuidSessionIdGenerator() ;
    }
​
    @Bean
    public SessionDAO sessionDAO(JavaUuidSessionIdGenerator javaUuidSessionIdGenerator){
        SessionDAO sessionDAO = new EnterpriseCacheSessionDAO() ;
        ((EnterpriseCacheSessionDAO) sessionDAO).setActiveSessionsCacheName("shiro-activeSessionCache");
        ((EnterpriseCacheSessionDAO) sessionDAO).setSessionIdGenerator(javaUuidSessionIdGenerator);
        return sessionDAO ;
    }
​
    @Bean
    public SimpleCookie simpleCookie(){
        SimpleCookie simpleCookie = new SimpleCookie("mldn-session-id") ;
        simpleCookie.setHttpOnly(true);
        simpleCookie.setMaxAge(-1);
        return simpleCookie ;
    }
​
    @Bean
    public SessionManager sessionManager(SimpleCookie simpleCookie, SessionDAO sessionDAO, EhCacheManager cacheManager){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager() ;
        sessionManager.setSessionIdCookie(simpleCookie);
        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setCacheManager(cacheManager);
        //session过期时间
        sessionManager.setGlobalSessionTimeout(60000*20);
        //session验证的时间间隔
        sessionManager.setSessionValidationInterval(60000*10);
        return sessionManager ;
    }
​
}

(四):自定义表单认证

指定登陆成功之后跳转的地址

``

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.getAndClearSavedRequest(request) ;//清理掉之前session保存的信息
        WebUtils.redirectToSavedRequest(request,response ,"/index" );
        return false;
    }
​
}

(五):登出处理

这里使用的时默认的登出处理

 

(六):shiro表的设计

 

user表

 

role表

 

user-role表

 

permission表

 

role-permission表

 

menu表

 

role-menu表

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值