前后端分离Springboot整合shiro -- 01基础使用

原创
2018/09/27 17:42
阅读数 4.7K

引入jar

        <!-- shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

继承AuthorizingRealm

编写自己的doGetAuthorizationInfo()和doGetAuthenticationInfo()方法

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.iretailer.model.User;
import com.iretailer.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * @author xjwtt
 * @date 2018/9/26
 */
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    /**
     * 获取用户的角色和权限
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    /**
     * 登录认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        /**
         * 获取输入的用户名和密码
         */
        String userName = (String) authenticationToken.getPrincipal();
        User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUsercode, userName));
        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误!");
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), getName());

        return info;
    }
}

配置ShiroConfig

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;

import java.util.LinkedHashMap;

/**
 * @author xjwtt
 * @date 2018/9/26
 */
@Configuration
public class ShiroConfig {

    /**
     * ShiroFilterFactoryBean 为Shiro过滤器工厂类
     * 配置一些过滤路径
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //配置shiro默认登录界面地址,前后端分离中登录界面跳转由端控制,后台仅返回json数据
        shiroFilterFactoryBean.setLoginUrl("/unauth.action");
        // 登录成功后跳转的url
//        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授权url
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //注意过滤器配置顺序 不能颠倒
        // 配置退出过滤器,其中具体的退出代码Shiro已经替我们实现了
//        前后端分离自己实现
//        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/login.action", "anon");
        filterChainDefinitionMap.put("/", "anon");
        //解析不需要认证
        filterChainDefinitionMap.put("/resolve", "anon");
        // 需要认证的url
        filterChainDefinitionMap.put("/**.action", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * SecurityManager 为shiro安全管理器,管理着所有的Subject
     *
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        //配置 SecurityManager 并注入 shrioRealm
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        return securityManager;
    }

    /**
     * 引入自己实现的 ShiroRealm
     *
     * @return
     */
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(matcher());
        return shiroRealm;
    }

    /**
     * 设置加密算法
     * @return
     */
    @Bean
    public HashedCredentialsMatcher matcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5"); //设置加密算法
        matcher.setHashIterations(1);//设置加密算法的次数
        return matcher;
    }

}

注意filterChain基于短路机制,即最先匹配原则如:

/user/**=anon
/user/aa=authc 永远不会执行

anon、authc等为Shiro实现的过滤器,具体如下

Filter Name Class Description
anon org.apache.shiro.web.filter.authc.AnonymousFilter 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例/static/**=anon
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter 基于表单的拦截器;如/**=authc,如果没有登录会跳到相应的登录页面登录
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter Basic HTTP身份验证拦截器
logout org.apache.shiro.web.filter.authc.LogoutFilter 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/),示例/logout=logout
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter 不创建会话拦截器,调用subject.getSession(false)不会有什么问题,但是如果subject.getSession(true)将抛出DisabledSessionException异常
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例/user/**=perms["user:create"]
port org.apache.shiro.web.filter.authz.PortFilter 端口拦截器,主要属性port(80):可以通过的端口;示例/test= port[80],如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter rest风格拦截器,自动根据请求方法构建权限字符串;示例/users=rest[user],会自动拼出user:read,user:create,user:update,user:delete权限字符串进行权限匹配(所有都得匹配,isPermittedAll)
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 角色授权拦截器,验证用户是否拥有所有角色;示例/admin/**=roles[admin]
ssl org.apache.shiro.web.filter.authz.SslFilter SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口443;其他和port拦截器一样;
user org.apache.shiro.web.filter.authc.UserFilter 用户拦截器,用户已经身份验证/记住我登录的都可;示例/**=user

跨域以及静态资源处理

import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.*;

import java.io.File;

/**
 * 配置 静态资源加载的路径
 * 跨域CORS配置
 * 某些请求不要拦截
 *
 * @author xjwtt
 * @date 2018/8/21
 */
@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 加载的静态资源路径
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String templatesPath = System.getProperty("user.dir") + "/" + "templates/";
        String staticPath = System.getProperty("user.dir") + "/" + "static/";
        File templatesFile = new File(templatesPath);
        File staticFile = new File(staticPath);
        if (templatesFile.exists()) {
            registry.addResourceHandler("/**").addResourceLocations("file:" + templatesPath);

        } else {
            registry.addResourceHandler("/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/templates/");
        }

        if (staticFile.exists()) {
            registry.addResourceHandler("/**").addResourceLocations("file:" + staticPath);

        } else {
            registry.addResourceHandler("/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/");

        }
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 跨域CORS设置
     *
     * @param registry
     */
    @Override
    //重写父类提供的跨域请求处理的接口
    public void addCorsMappings(CorsRegistry registry) {
        //添加映射路径
        registry.addMapping("/**")
                .allowedHeaders("*")
                //是否发送Cookie信息
                .allowCredentials(true)
                //放行哪些原始域(请求方式)
                .allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
                //放行哪些原始域
                .allowedOrigins("*")
                //放行哪些原始域(头部信息)
                .allowedHeaders("*");
    }
}
展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部