引入jar
org.apache.shiro
shiro-spring
1.4.0
继承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().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 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("*");
}
}