60%企业都在使用springboot
(1)依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lqh</groupId>
<artifactId>day0805-shiro-springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>day0805-shiro-springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
</dependency>
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)application.yml配置文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai
username: root
password: pAssW0rd
server:
port: 8080
servlet:
context-path: /lqh
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
(3)创建shiro配置类
package com.lqh.config;
//import com.lqh.filter.LoginFilter;
import com.lqh.filter.LoginFilter;
import com.lqh.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
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 javax.servlet.Filter;
import java.util.HashMap;
/**
* @Author Li Qinghua
* @Create 2022/8/5 15:52
*/
@Configuration
public class ShiroConfig {
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
@Bean
public Realm realm(){
MyRealm myRealm=new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher());
return myRealm;
}
@Bean
public CredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(1024);
return credentialsMatcher;
}
@Bean(value = "shiroFilter")
public ShiroFilterFactoryBean filterFactoryBean(){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager());
//设置拦截规则
HashMap<String,String> map=new HashMap<>();
map.put("/login","anon");
map.put("/*.css","anon");
map.put("/doc.html","anon");
map.put("/v2/api-docs","anon");
map.put("/configuration/security", "anon");
map.put("/swagger-resources","anon");
map.put("/swagger-ui.html","anon");
map.put("/configuration/ui","anon");
map.put("/webjars/springfox-swagger-ui/**","anon");
map.put("/**","authc");
factoryBean.setFilterChainDefinitionMap(map);
//设置自定义认证过滤器
HashMap<String,Filter> filterMap=new HashMap<String, Filter>();
filterMap.put("authc",new LoginFilter());
factoryBean.setFilters(filterMap);
return factoryBean;
}
@Bean //注册filter
public FilterRegistrationBean<Filter> filterRegistrationBean(){
FilterRegistrationBean<Filter> filterRegistrationBean=new FilterRegistrationBean<>();
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
//开始shiro注解
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
}
(3)创建controller service dao entity 自动生成
package com.lqh;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class Generator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/shiro-permission?serverTimezone=Asia/Shanghai", "root", "123456")
.globalConfig(builder -> {
builder.author("李青华") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir(".\\src\\main\\java\\"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.lqh") // 设置父包名
//.moduleName("system") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("acl_user","acl_role","acl_permission")// 设置需要生成的表名
.addTablePrefix("acl_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
(4)创建realm
package com.lqh.realm;
import com.lqh.entity.User;
import com.lqh.sever.UserServer;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @Author Li Qinghua
* @Create 2022/8/5 15:54
*/
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserServer userServer;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
//根据账号查询该用户具有哪些权限
List<String> list= userServer.findPermissionByUsername(user.getUserid());
if(list!=null&&list.size()>0){
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(list);
return info;
}
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1.根据token获取账号
String username = (String) token.getPrincipal();
//2.根据账号查询用户信息
User user = userServer.findByUsername(username);
if(user!=null){
//从数据库中获取的密码
ByteSource credentialsSalt= ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),credentialsSalt,this.getName());
return info;
}
return null;
}
}
404问题
开启shiro注解
//开始shiro注解
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
使用swagger进行登录测试和权限测试
坑: doc.html无法访问以及样式无效。 shiro拦截规则拦截了
@Bean(value = "shiroFilter")
public ShiroFilterFactoryBean filterFactoryBean(){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager());
//设置拦截规则
HashMap<String,String> map=new HashMap<>();
map.put("/login","anon");
map.put("/*.css","anon");
map.put("/doc.html","anon");
map.put("/v2/api-docs","anon");
map.put("/configuration/security", "anon");
map.put("/swagger-resources","anon");
map.put("/swagger-ui.html","anon");
map.put("/configuration/ui","anon");
map.put("/webjars/springfox-swagger-ui/**","anon");
map.put("/**","authc");
factoryBean.setFilterChainDefinitionMap(map);
//设置自定义认证过滤器
HashMap<String,Filter> filterMap=new HashMap<String, Filter>();
filterMap.put("authc",new LoginFilter());
factoryBean.setFilters(filterMap);
return factoryBean;
}
(5)创建Login过滤器
package com.lqh.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lqh.utils.CommonResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;
/**
* @Author Li Qinghua
* @Create 2022/8/5 16:26
*/
public class LoginFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
CommonResult commonResult = new CommonResult(401, "未登录", null);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(commonResult);
writer.print(json);
writer.flush();
writer.close();
return false;
}
}
(6)创建拦截器
package com.lqh.handler;
import com.lqh.utils.CommonResult;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Author Li Qinghua
* @Create 2022/8/5 17:02
*/
@ControllerAdvice
public class MyException {
@ExceptionHandler(value = UnauthorizedException.class)
@ResponseBody
public CommonResult auth(UnauthorizedException e){
e.printStackTrace();
return new CommonResult(402,"权限不足",null);
}
}