springboot整合shiro重要的是shiro配置文件的编写
添加需要的jar包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!--thymeleaf整合shiro的依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
编写shiro配置类
package com.jws.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.jws.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import java.util.HashMap;
import java.util.Map;
/**
* @author Jin
* @date 2020/11/11 15:16
* @packageName: com.jws.config
* @cLassName: MyConfig
* @description:
* @version:
*/
@Configuration
public class ShiroConfiguration {
/**
* 创建密码匹配器
* @return
*/
@Bean(value = "credentialsMatcher")
public HashedCredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(2);
return credentialsMatcher;
}
/**
* 创建一个realmBean,自定义类
* @param credentialsMatcher
* @return
*/
@Bean(value = "myRealm")
public Realm realm(CredentialsMatcher credentialsMatcher){
MyRealm myRealm=new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);
return myRealm;
}
/**
* 创建securityManager核心对象bean
* @param myRealm
* @return securityManager
*/
@Bean(value = "securityManager")
public DefaultWebSecurityManager securityManager(Realm myRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
/**
* 这里bean的value值一定要与下面注册filterBean时添加shiro过滤器(TargetBeanName)的名字一致
* @param securityManager
* @return
*/
@Bean(value = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//前后端分离时不需要设置
shiroFilterFactoryBean.setLoginUrl("/index.html");
shiroFilterFactoryBean.setSecurityManager(securityManager);
//定义一个map设置请求的权限
Map<String, String> map=new HashMap<>();
map.put("/tologin","anon");
map.put("/login","anon");
map.put("/logout","logout");
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean(){
FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean=new FilterRegistrationBean<>();
DelegatingFilterProxy delegatingFilterProxy=new DelegatingFilterProxy();
//与上面配置的shiro过滤器bean的名字一致
delegatingFilterProxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(delegatingFilterProxy);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
/**
* 这里是为了能在html页面引用shiro标签,
*/
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
application.properties
server.port=8080
#配置数据源characterEncoding=utf8&useSSL=true&serverTimezone=UTC
spring.datasource.druid.url=jdbc:mysql://localhost:3306/test2?serverTimezone=Asia/Shanghai
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=0207
mybatis.mapper-locations=classpath:mapper/*xml
#清除thymeleaf缓存,实时显示页面
spring.thymeleaf.cache=false
controller代码
@Controller
public class MyController {
/**
* 可以给一个登陆页面方便测试
* @return
*/
@GetMapping("login")
public String login(){
return "login";
}
@GetMapping("main")
public @ResponseBody CommonResult main(HttpSession session){
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
session.setAttribute("user",user);
return new CommonResult(200,"登陆成功");
}
@GetMapping("logout")
public @ResponseBody CommonResult logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return new CommonResult(200,"退出成功");
}
@GetMapping("tologin")
public String toLogin(String username, String password){
try {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
subject.login(token);
return "redirect:main";
}catch (Exception e){
return "redirect:login";
}
}
@GetMapping("query")
@RequiresPermissions(value = "user:query")
public @ResponseBody String query(){ return "user:query";}
@GetMapping("insert")
@RequiresPermissions(value = "user:insert")
public @ResponseBody String insert(){ return "user:insert";}
@GetMapping("delete")
@RequiresPermissions(value = "user:delete")
public @ResponseBody String delete(){ return "user:delete";}
@GetMapping("update")
@RequiresPermissions(value = "user:update")
public @ResponseBody String update(){ return "user:update";}
@GetMapping("export")
@RequiresPermissions(value = "user:export")
public @ResponseBody String export(){ return "user:export";}
}
验证未登录时继承shiro提供的未认证过滤器来处理未认证请求
public class LoginFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json; charset=UTF-8");
CommonResult commonResult=new CommonResult(500,"未登录");
response.getWriter().println(JSON.toJSONString(commonResult));
return false;
}
}
CommonResult实体类用来返回前端需要的json数据
public class CommonResult {
//状态码
private int status;
//消息
private String message;
//是否成功
private Boolean success;
//存储数据
private Map<String,Object> data=new HashMap<>();
public CommonResult(int status, String message) {
this.status = status;
this.message = message;
}
//链式编程
public static CommonResult ok(){
CommonResult commonResult=new CommonResult();
commonResult.status=200;
commonResult.message="成功";
commonResult.success=true;
return commonResult;
}
//
public static CommonResult error(){
CommonResult commonResult=new CommonResult();
commonResult.status=500;
commonResult.message="失败";
commonResult.success=false;
return commonResult;
}
public CommonResult message(String msg){
this.message=msg;
return this;
}
public CommonResult status(Integer code){
this.status =code;
return this;
}
public CommonResult success(Boolean success){
this.success=success;
return this;
}
//存放数据
public CommonResult put(String key,Object d){
this.data.put(key,d);
return this;
}
}
定义一个异常类来处理未授权异常
@RestControllerAdvice
public class HandlerGlobaleException {
@ExceptionHandler(value = UnauthorizedException.class)
public CommonResult handler(){
return new CommonResult(500,"未授权");
}
}