SpringBoot结合Shiro
先了解Shiro是什么
shiro是一个安全框架,可以进行认证、授权、密码加密、会话管理
功能:
Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
对应的pom文件
< dependency>
< groupId>org.apache.shiro</ groupId>
< artifactId>shiro-spring</ artifactId>
< version>1.4.0</ version>
</ dependency>
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
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.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroBean {
@Bean
public MyRealm authRealm() {
MyRealm realm = new MyRealm();
return realm;
}
@Bean("securityManager")
public DefaultWebSecurityManager getManager(MyRealm realm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
// 使用自己的realm
manager.setRealm(realm);
/*
* 关闭shiro自带的session,详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
manager.setSubjectDAO(subjectDAO);
return manager;
}
/**
* Shiro自定义拦截器
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiorFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
//shiroFilterFactoryBean.setLoginUrl("/login");
//配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
shiroFilterFactoryBean.setLoginUrl("/login/loadHtml");
shiroFilterFactoryBean.setUnauthorizedUrl("/login/loadHtml");
// 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//配置记住我或认证通过可以访问的地址(配置不会被拦截的链接 顺序判断)
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/images/**", "anon");
filterChainDefinitionMap.put("/face/**", "anon");
filterChainDefinitionMap.put("/lay/**", "anon");
filterChainDefinitionMap.put("/modules/**", "anon");
filterChainDefinitionMap.put("/layui/**", "anon");
filterChainDefinitionMap.put("/nepadmin/**", "anon");
//C:\Develop\workspace\cr\paodingsoft\trunk\demo\spring-boot-api-project-seed-master\src\main\resources\static\js\lib\jquery-easyui-1.7.1\jquery.easyui.min.js
// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/login/loginFile", "anon");
// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 下面的代码是添加注解支持
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
// 强制使用cglib,防止重复代理和可能引起代理出错的问题
// https://zhuanlan.zhihu.com/p/29161098
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* cookie对象;
* 记住密码实现起来也是比较简单的,主要看下是如何实现的。
*
* @return
*/
@Bean
public SimpleCookie rememberMeCookie() {
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
@Bean
public SecurityManager securityManagerC() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(authRealm());
//注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManagerC());
return advisor;
}
}
这里如果是新手应该会出现一个问题:
如果Shiro找不到对应的登录页面的话,会启动它自带的登陆页(shiorFilter这个方法里面配置对应的跳转路径,以给出注解,不懂私信我)
还有一个就是Shiro会重定向你的地址,如果在未登录的情况下(你下面所有的路径都会报302错误,将你所有的静态资源全部放过去,shiorFilter这个方法里面配置对应的跳转路径,以给出注解,不懂私信我)
下一步配置功能代码
import com.company.project.dao.TbSysUserMapper;
import com.company.project.model.TbSysUser;
import com.company.project.service.TbSysDeptService;
import com.company.project.service.TbSysUserService;
import com.company.project.util.JWTUtil;
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.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Resource;
public class MyRealm extends AuthorizingRealm {
@Autowired
private TbSysUserService server;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = JWTUtil.getUsername(principals.toString());
System.out.println(username);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermission("1212312");
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String name =(String) token.getPrincipal();
TbSysUser user=server.findBy("userName",name);
System.out.println(user.getPassword());
if(user!=null){
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(name, user.getPassword(),"xxx");
return authcInfo;
}else{
return null;
}
}
}
记住这两个方法一定要有返回值,如果没有返回值会导致接口Controller报错
如果返回空值可以利用作为空值判断,然后在Controller做try-catch处理
Controller接口类
@RequestMapping("/loginFile")
@ResponseBody
public String getIsOkToTemp(@RequestParam(name=“name”,required=false)String name,@RequestParam(name=“pwd”,required=false) String pwd, @RequestParam(name=“autoLogin”,required=false,defaultValue=“No”) String autoLogin){
UsernamePasswordToken token = new UsernamePasswordToken(name, MD5Util.encrypt(pwd));
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
String userName = (String) subject.getPrincipal();
TbSysUser currentUser =null;
return “tableHtml”;
} catch (Exception e) {
System.out.println(1111);
e.printStackTrace();
return “{error:404,message:‘The Account Is Not Exist Or The Password Is Error’}”;
}
}
如果不做处理返回null Subject subject = SecurityUtils.getSubject();这个方法会报错
Shiro配置就完成了,记住登录操作它会自动记录
不然你访问的任何项目连接都会重定向到你所配置的登录页
不懂私信我,滴滴我