前言
在实际开发中,往往一些操作需要用户的一定权限才能进行。因为这种场景的存在,所以衍生除了一系列安全框架,而其中最常用的无外乎两种:shiro
和spring security
。
两种框架提供的功能都比较强大。但相比spring security
来说,shiro
的API更简单,更轻量级。
Shiro
在shiro
中,核心类主要有以下三个
Subject: 授权主体。在web应用中,表示当前登录用户。
**SecurityManager:**安全管理器。管理用户的安全相关操作,如登陆,登出等。
**Realm:**处理用户的认证过程。主要是根据登录信息获取实际用户的基础以及权限相关信息。
具体编码
准备阶段
添加依赖
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'org.apache.shiro:shiro-core:1.4.0'
compile 'org.apache.shiro:shiro-spring:1.4.0'
新增TestController.java
TestController.java
package com.boot.demo.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@Controller
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@RequestMapping("auth/login")
public ModelAndView login(HttpServletRequest request){
SecurityUtils.getSubject().logout();
ModelAndView mv = new ModelAndView();
String error = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
logger.info("error : {}",error);
if(null != error && !"".equals(error)){
if(UnknownAccountException.class.getName().equals(error)){
mv.addObject("error","账号不存在");
} else if(IncorrectCredentialsException.class.getName().equals(error)){
mv.addObject("error","密码错误");
}
}
mv.setViewName("auth/login");
return mv;
}
@RequestMapping("test")
@ResponseBody
public String test(){
logger.info("登录信息 principal : {}", SecurityUtils.getSubject().getPrincipal());
return "Hello World";
}
}
在src/main/resources下,新增templates/auth/login.html
templates/auth/login.html
<!DOCTYPE html>
<html>
<head>
<title>登录界面</title>
</head>
<body>
<span style="color:red" th:if="not ${#strings.isEmpty(error)}" th:text="${error}">错误信息</span>
<form method="post" action="/auth/login">
<div>
<label>用户名:</label>
<input type="text" name="username"/>
</div>
<div>
<label>密码:</label>
<input type="password" name="password"/>
</div>
<input type="submit" value="登录">
</form>
</body>
</html>
新增主函数
BootApplication.java
package com.boot.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 整合shiro
* Author : Ivan
**/
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class,args);
}
}
整合Shiro
ShiroConfig.java
package com.boot.demo.config;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@Bean
public Realm realm(){
//这里只为测试
//所以用的是SimpleAccountRealm
//实际开发中,一般自定义Realm
SimpleAccountRealm realm = new SimpleAccountRealm();
realm.addAccount("user","123456","USER");
realm.addAccount("admin","123456","ADMIN");
return realm;
}
@Bean
public SecurityManager securityManager(Realm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/auth/login");
shiroFilter.setFilterChainDefinitionMap(getFilterChainDefinitionMap());
return shiroFilter;
}
private Map<String,String> getFilterChainDefinitionMap(){
Map<String,String> filterChainMap = new LinkedHashMap<>();
filterChainMap.put("/auth/login","authc");
filterChainMap.put("/auth/logout","logout");
filterChainMap.put("/**","user");
return filterChainMap;
}
}
测试
好了,到这里,Spring Boot
整合shiro
的编码就完成了。接下来,我们启动项目看看吧
启动后,访问http://localhost:8080/test,页面会重定向至http://localhost:8080/auth/login
输入错误账号
输入错误密码
登录成功后,再次访问http://localhost:8080/test
最后,访问http://localhost:8080/auth/logout,可退出用户