shiro+SpringBoot+Mybatis-plus
- 一、pom.xml
- 二、application.properties
- 三、shiro的組態檔
- 四、html檔案
- 五、后端各層檔案
- 六、將專案改造成前后端完全分離
首先創建springboot專案,匯入相關依賴,
專案結構:

訪問流程:
專案啟動類:
@SpringBootApplication
@MapperScan(value = "com.fy.dao")
public class SbMyShiroApplication {
public static void main(String[] args) {
SpringApplication.run(SbMyShiroApplication.class, args);
}
}
一、pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>5.1.47</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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>
</dependencies>
二、application.properties
#配置資料源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/ssm_shiro
spring.datasource.druid.password=root
spring.datasource.druid.username=root
#日志
logging.level.com.fy.dao=debug
#映射檔案地址
mybatis-plus.mapper-locations=classpath*:/mapper/*.xml
三、shiro的組態檔
在ssm專案中,shiro的組件創建在spring組態檔中,在springboot專案中,需要自己創建一個配置類
//這個注解讓該類相當于spring的組態檔
@Configuration
public class ShiroConfig {
// 配置安全管理器
@Bean(value = "SecurityManager")
public DefaultWebSecurityManager getSecurityManager(MyRealm MyRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 將realm交給安全管理器管理
securityManager.setRealm(MyRealm);
return securityManager;
}
// 創建MyRealm物件
@Bean(value = "MyRealm")
public MyRealm getMyRealm(HashedCredentialsMatcher CredentialsMatcher){
MyRealm myRealm = new MyRealm();
// 給Realm配置密碼匹配器
myRealm.setCredentialsMatcher(CredentialsMatcher);
return myRealm;
}
// 創建密碼匹配器
@Bean(value = "CredentialsMatcher")
public HashedCredentialsMatcher getCredentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(1024);
return credentialsMatcher;
}
// 配置過濾規則
@Bean(value = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactory(SecurityManager SecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 設定要過濾的安全管理器
shiroFilterFactoryBean.setSecurityManager(SecurityManager);
// 未登錄訪問的跳轉路徑
shiroFilterFactoryBean.setLoginUrl("/tologin");
// 登錄成功時訪問的路徑
shiroFilterFactoryBean.setSuccessUrl("/success.html");
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("/login.html","anon");
hashMap.put("/login","anon");
hashMap.put("/static/**","anon");
hashMap.put("/**","authc");
// 其他需要設定的路徑
shiroFilterFactoryBean.setFilterChainDefinitionMap(hashMap);
return shiroFilterFactoryBean;
}
// 配置過濾器 相當于ssm專案中web.xml的給shiro配置過濾器
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
//springboot專案只能使用html頁面,使shiro標簽庫可以在thymeleaf中使用
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
四、html檔案
springboot專案不支持jsp,只能使用html,要使用thymeleaf模板,需要匯入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
1、login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
賬號:<input type="text" name="username"/><br>
密碼:<input type="text" name="userpwd"/><br>
<input type="submit" value="登陸"/>
<input type="button" value="注冊" onclick="location.href='regist'"/>
</form>
</body>
</html>
2、success.html
在這個頁面中需要使用shiro的標簽,要在頁面中引入shiro的標簽,也要在pom.xml中引入依賴
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!DOCTYPE html>
<!--引入shiro的標簽-->
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登陸成功 <h1>歡迎來到</h1>
<shiro:hasPermission name="user:query">
<a href="/user/query">查詢所有用戶</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<a href="/user/update">修改用戶</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete">
<a href="/user/delete">洗掉用戶</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:insert">
<a href="/user/insert">添加用戶</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:export">
<a href="/user/export">匯出用戶</a><br>
</shiro:hasPermission>
</body>
</html>
3、un.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
無權訪問
</body>
</html>
五、后端各層檔案
1、dao
①UserDao
public interface UserDao extends BaseMapper<User> {
/**
* 根據用戶id查詢該用戶具有的權限
* @param userid
* @return
*/
List<String> findPermissionByUserid(Integer userid);
}
2、entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer userid;
private String username;
private String userpwd;
private String sex;
private String address;
private String salt; //鹽
}
3、service
UserService介面
public interface UserService{
User selectOne(String username);
List<String> findPermissionByUserid(Integer userid);
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao;
// 使用的mybatis-plus中的方法
@Override
public User selectOne(String username) {
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",username);
User user = userDao.selectOne(wrapper);
return user;
}
@Override
public List<String> findPermissionByUserid(Integer userid) {
return userDao.findPermissionByUserid(userid);
}
}
4、user的映射檔案
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fy.dao.UserDao">
<select id="findPermissionByUserid" resultType="String">
select percode from user_role ur,role_permission rp, permission p
where ur.roleid=rp.roleid and rp.perid=p.perid and ur.userid=#{userid}
</select>
</mapper>
5、Controller層
①LoginController: 登錄業務
@Controller
public class LoginController {
private UsernamePasswordToken token;
@PostMapping("/login")
public String login(String username,String userpwd){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, userpwd);
try {
subject.login(token);
return "success";
}catch (Exception e){
return "login";
}
}
}
②PageController: 未登錄時跳轉到login.html
@Controller
public class PageController {
@RequestMapping("tologin")
public String tologin(){
System.out.println("");
return "login";
}
}
③UserController:
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping("query")
@RequiresPermissions("user:query")
public String query(){
return "user:query";
}
@GetMapping("delete")
@RequiresPermissions("user:delete")
public String delete(){
return "user:delete";
}
@GetMapping("update")
@RequiresPermissions("user:update")
public String update(){
return "user:update";
}
@GetMapping("insert")
@RequiresPermissions("user:insert")
public String insert(){
return "user:insert";
}
@GetMapping("export")
@RequiresPermissions("user:export")
public String export(){
return "user:export";
}
}
6、handler層
ExceptionController : 處理例外
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(value = AuthorizationException.class)
public String handler(){
return "un";
}
}
7、realm層
MyRealm.java
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userServiceimpl;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user =(User) principals.getPrimaryPrincipal();
List<String> permission = userServiceimpl.findPermissionByUserid(user.getUserid());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if(permission.size()>0){
info.addStringPermissions(permission);
}
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = token.getPrincipal().toString();
User user = userServiceimpl.selectOne(username);
if(user!=null){
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName());
return info;
}
return null;
}
}
六、將專案改造成前后端完全分離
前后端完成分離,后端回傳給訪問者的是json資料
該專案中有三個地方需要改造回傳json資料:
1、認證成功或認證失敗時
2、出現例外時,例如權限不足時
3、未登錄訪問時
操作:
1、創建回傳的json資料格式
utils層-----》CommonResult.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult {
private Integer code;
private String msg;
private Object data;
}
2、改造Controller
將Controller層的@Controller都改成@RestController,將@ControllerAdvice改成@RestControllerAdvice
①、LoginController
@PostMapping("login")
public CommonResult login(String username, String userpwd){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(username,userpwd);
try {
subject.login(token);//realm的認證功能
//getPrincipl()可以得到SimpleAuthenticationInfo中的資料
Object user = subject.getPrincipal();
return new CommonResult(2000,"登陸成功",user);
}catch (Exception e){
return new CommonResult(5000,"登陸失敗",null);
}
}
②、ExceptionController 例外處理類
@RestControllerAdvice
public class MyHandlerException {
@ExceptionHandler(value = UnauthorizedException.class)
public CommonResult unauthorizedException(){
return new CommonResult(5001,"權限不足",null);
}
}
③、未登錄訪問時回傳json有兩種改造方式
第一種:改PageController
@RestController
public class PageController {
@GetMapping("/tologin")
public CommonResult loginPage(){
return new CommonResult(5002,"請先登錄",null);
}
}
第二種:改ShiroConfig檔案,創建一個過濾器
ShiroConfig.java中改過濾規則中的內容,加上過濾器配置
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/tologin");
shiroFilterFactoryBean.setSuccessUrl("/success.html");
Map<String,String> map=new HashMap<>();
map.put("/index.html","anon");
map.put("/static/**","anon");
map.put("/login","anon"); //anon表示放行
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//未登錄時的過濾器
Map<String, Filter> filterMap=new HashMap<>();
filterMap.put("authc",new LoginFilter());
shiroFilterFactoryBean.setFilters(filterMap);
return shiroFilterFactoryBean;
}
在filter層創建一個過濾器:
LoginFilter.java
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(5002,"未登錄",null);
response.getWriter().print(JSON.toJSONString(commonResult));
return false;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/274518.html
標籤:其他
