springboot技术栈
示例源码
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序
在springboot中集成
- 引入shiro及shiro-redis开发包
<!--shiro-->
<dependency>
<groupId></groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--shiro-redis-->
<dependency>
<groupId></groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
- 中配置redis信息
spring:
redis:
hostName: 123.206.19.217
port: 6379
password:
timeout: 5000
- 新建Shiro配置文件
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 开发公司:青岛海豚数据技术有限公司
* 版权:青岛海豚数据技术有限公司
* <p>
* ShiroConfig
*
* @author 刘志强
* @created Create Time: 2019/2/16
*/
@Configuration
public class ShiroConfig {
@Value("${}")
private String host;
@Value("${}")
private int port;
@Value("${}")
private int timeout;
@Value("${}")
private String password;
/**
* shirFilter过滤器
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
//注意过滤器配置顺序 不能颠倒
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
("/shiro/logout2", "logout");
// 配置不会被拦截的链接 顺序判断
("/static/**", "anon");
(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean(name = "securityManager")
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
(myShiroRealm());
// 自定义session管理 使用redis
(sessionManager());
// 自定义缓存实现 使用redis
(cacheManager());
return securityManager;
}
//自定义sessionManager
@Bean
public SessionManager sessionManager() {
SessionConfig mySessionManager = new SessionConfig();
(redisSessionDAO());
return mySessionManager;
}
/**
* 配置shiro redisManager
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
(host);
(port);
// (18000);// 配置缓存过期时间
(timeout);
(password);
return redisManager;
}
/**
* cacheManager 缓存 redis实现
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
(redisManager());
return redisCacheManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* <p>
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
(redisManager());
return redisSessionDAO;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
用redis实现缓存管理
- 新建DefaultWebSessionManager继承类,自定义getSessionId方法,以实现基于token登录。
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 开发公司:青岛海豚数据技术有限公司
* 版权:青岛海豚数据技术有限公司
* <p>
* SessionConfig
*
* @author 刘志强
* @created Create Time: 2019/2/16
*/
public class SessionConfig extends DefaultWebSessionManager {
public SessionConfig() {
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = (request).getHeader("token");
if (!(id) && !"null".equals(id)) {
(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "Stateless request");
(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, );
return id;
} else {
//否则按默认规则从cookie取sessionId
return (request, response);
}
}
}
- 新建验证及授权类 MyShiroRealm 集成 AuthorizingRealm
package ;
import ;
import ;
import .;
import .*;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 开发公司:青岛海豚数据技术有限公司
* 版权:青岛海豚数据技术有限公司
* <p>
* MyShiroRealm
*
* @author 刘志强
* @created Create Time: 2019/2/16
*/
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
AdminUserMapper adminUserMapper;
public MyShiroRealm() {
super();
}
/**
* 认证信息,主要针对用户登录,
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken utoken = (UsernamePasswordToken) authcToken;
AdminUser adminUser = new AdminUser();
(());
(new String(()));
//根据账号密码查用户信息
AdminUser user = (adminUser);
if (null == user) {
throw new AccountException("账号不存在!");
} else if (!((), ())) {
throw new AccountException("密码不正确!");
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo((),// 用户名
(), // 密码
getName());
return simpleAuthenticationInfo;
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
String userName = ().toString().split(":")[0];
//根据用户userName查询权限(permission) 此处省略sql写固定权限
Set<String> permissions = new HashSet<>();
("shiro:all");
(permissions);
return info;
}
}
- 定义一个全局异常处理类来处理shiro异常。。AdviceController
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 开发公司:青岛海豚数据技术有限公司
* 版权:青岛海豚数据技术有限公司
* <p>
* AdviceController
*
* @author 刘志强
* @created Create Time: 2019/2/16
*/
@RestController
@ControllerAdvice
public class AdviceController {
@Autowired
public HttpServletResponse httpServletResponse;
/**
* shiro权限错误
* @param ex
* @return
*/
@ExceptionHandler()
@CrossOrigin
public String authorizationException(AuthorizationException ex) {
if (ex instanceof UnauthenticatedException) {
// try {
// ("/shiro/login");
// } catch (IOException e) {
// ();
// return "token错误或未登录";
// }
return "token错误或未登录";
} else if (ex instanceof UnauthorizedException) {
return "用户无权限";
} else {
return ();
}
}
}
- 建立shiro测试controller
package ;
import ;
import ;
import ;
import ;
import ;
import .*;
import ;
import ;
import ;
import ;
/**
* 开发公司:青岛海豚数据技术有限公司
* 版权:青岛海豚数据技术有限公司
* <p>
* ShiroController
*
* @author 刘志强
* @created Create Time: 2019/2/16
*/
@RestController
@RequestMapping("/shiro")
public class ShiroController {
@GetMapping("/login")
public ModelAndView login() {
return new ModelAndView("/freemarker/login");
}
/**
* 验证用户信息,用于登陆
*
* @param adminUser
* @return
*/
@PostMapping("/verificationUser")
public String verificationUser(AdminUser adminUser) {
//验证用户信息
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken((), ());
Subject subject = ();
Map<String, Object> map = new HashMap<String, Object>();
try {
//完成登录
(usernamePasswordToken);
return ().getId().toString();
} catch (Exception e) {
return ();
}
}
@GetMapping("shiroAll")
@RequiresPermissions("shiro:all")
@ResponseBody
public Map<String,Object> shiroAll(){
Subject subject = ();
String UserName = ().toString().split(":")[0];
Map<String,Object> map = new HashMap<>();
("userName", UserName);
("value", "有权限");
return map;
}
@GetMapping("noAuthority")
@RequiresPermissions("noAuthority")
@ResponseBody
public Map<String,Object> noAuthority(){
Subject subject = ();
String UserName = ().toString().split(":")[0];
Map<String,Object> map = new HashMap<>();
("value", "无权限");
("userName", UserName);
return map;
}
/**
* 手动退出
* @param httpServletRequest
* @return
*/
@GetMapping("logout")
public String logout(HttpServletRequest httpServletRequest) {
Subject subject = ();
();
return "退出成功";
}
/**
* 自动退出 退出后会重定向到跟目录
* @return
*/
@GetMapping("logout2")
public String logout2() {
return "退出成功";
}
}
-
访问接口测试权限
-
如果前后端分离, headers里携带token。。token值是verificationUser接口返回的值