【详细版】SpringBoot整合shiro
首先展示下我的项目结构
第一步导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<fastjson.version>1.2.47</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--shiro与spring整合 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!--shiro与redis整合实现sessionDao -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<!--编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!--单元测试插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
第二步
编写yml文件,这里的配置文件配置了数据源和项目名端口号之类。大家可自行设置
第三步
编写Shiro的配置文件,这里的@Configuration,相当于spring里的spring-shiro.xml。里面配置了安全管理器,自定义realm
package cn.itcast.shiro.config;
import cn.itcast.shiro.service.CustomerRealm;
import org.apache.shiro.realm.Realm;
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.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给ShiroFilter配置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//配置系统受限资源
//配置系统公共资源
Map<String, String> map = new HashMap<String, String>();
map.put("/index.jsp","authc");//表示这个资源需要认证和授权
// 设置认证界面路径
shiroFilterFactoryBean.setLoginUrl("/login.jsp");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//创建安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//创建自定义Realm
@Bean
public Realm getRealm() {
CustomerRealm realm = new CustomerRealm();
return realm;
}
}
第四步
自定义的realm,里面的doGetAuthenticationInfo是shiro里的认证方法,其中subject.login()。这一句后面会跳转到这里做安全认证
package cn.itcast.shiro.service;
import cn.itcast.shiro.dao.UserDao;
import cn.itcast.shiro.domain.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 自定义Realm
*/
public class CustomerRealm extends AuthorizingRealm {
@Autowired
private UserDao userDao;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//参数authenticationToken就是传递的subject.login(token)中的参数
UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
//从token中获取用户名
String username=token.getUsername();
//根据用户名查询用户的安全数据(数据库中的用户数据)
User user= userDao.findByUsername(username);
if(user==null){
return null;
}
AuthenticationInfo info=new SimpleAuthenticationInfo(//将密码封装为shiro需要的格式
username,//当前用户用户名,跟上面的doGetAuthorizationInfo方法是对应的
user.getPassword(),//从数据库查询出来的安全密码
getName());
return info;
}
}
第五步 编写controller,service,dao.开始实现
controller
package cn.itcast.shiro.controller;
import cn.itcast.shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class UserController {
@Autowired
private UserService userService;
//添加
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String add() {
return "添加用户成功";
}
//查询
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String find() {
return "查询用户成功";
}
//更新
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public String update(String id) {
return "更新用户成功";
}
//删除
@RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
public String delete() {
return "删除用户成功";
}
//用户登录
@RequestMapping(value="/login")
public String login(@RequestBody Map<String,String> loginMap) {
try {
String username = loginMap.get("username");
String password = loginMap.get("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken uptoken = new UsernamePasswordToken(username, password);
subject.login(uptoken);
return "登录成功";
} catch (Exception e) {
return "用户名或密码错误";
}
}
}
service
package cn.itcast.shiro.service;
import cn.itcast.shiro.dao.UserDao;
import cn.itcast.shiro.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User findByName(String name) {
return this.userDao.findByUsername(name);
}
public List<User> findAll() {
return userDao.findAll();
}
}
dao
package cn.itcast.shiro.dao;
import cn.itcast.shiro.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* 用户数据访问接口
*/
public interface UserDao extends JpaRepository<User, String>, JpaSpecificationExecutor<User> {
//根据手机号获取用户信息
User findByUsername(String name);
}