社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
今天第一次接触springboot,本来是要学习springboot和shiro整合的,但是由于springboot结构还不太了解,所以先来了解一下springboot。
springboot可以快速创建一个机遇spring的项目,而且让这个项目跑起来只需要很少的配置就可以了,主要有以下核心功能:
1.独立运行的spring项目:springboot可以以jar包的形式来运行,运行一个springboot项目我们只需要通过jar -jar xx.jar类运行。
2.Spring Boot可以内嵌Tomcat,这样我们无需以war包的形式部署项目。
3.提供starter简化Maven配置:使用Spring或者SpringMVC我们需要添加大量的依赖,而这些依赖很多都是固定的,这里Spring Boot 通过starter能够帮助我们简化Maven配置。
4.自动配置Spring 。
5.准生产的应用监控 。
6.无代码生成和xml配置。
下面就是开始搭建环境了
1、先建一个springboot工程
修改项目group和artifact
选择所需要的依赖
再选择一下工作空间就完成了
idea创建springboot项目自带项目入口,不用自己配置
修改一下入口类,运行就能在浏览器里访问该项目了,注意要在入口类加上一个@RestController的注解
package com.jiang.springboot_shiro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class SpringbootShiroApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootShiroApplication.class, args);
}
@RequestMapping(value = "/springboot_shiro",produces = "text/plain;charset=UTF-8")//项目访问URL
public String index(){
return "Hello springboot!";
}
}
现在在浏览器里面输入localhost:8080/springboot_shiro就能看到返回的Hello springboot!
上面这种方式是把入口类作为控制类,如果要将控制器和入口类分离,控制器的包一定要跟启动类是同一目录,如下:
接下来是整合shiro进行认证,代码会在之前的代码上有所改动
pom.xml添加需要的包
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jiang</groupId>
<artifactId>springboot_shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot_shiro</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
先建一个user表,在user表中加了一列权限
由于我的是集成了mybatis的,所以要先配置springboot的配置文件
application.properties
#spring集成mybatis环境
mybatis.type-aliases-package=com.jiang.springboot_shiro.entity
#加载mybatis配置文件
mybatis.mapper-locations=classpath:mapper/*.xml
#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/chun?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=
entity.java
package com.jiang.springboot_shiro.entity;
public class User {
private String name;
private String password;
private String authority;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public String getAuthority() {
return authority;
}
}
mapper.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.jiang.springboot_shiro.mapper.UserMapper">
<resultMap id="user" type="User">
<result property="name" column="name"></result>
<result property="password" column="password"></result>
</resultMap>
<select id="findUser" resultType="User" resultMap="user">
select * from user where name =#{name} and password=#{password}
</select>
</mapper>
mapper.java
package com.jiang.springboot_shiro.mapper;
import com.jiang.springboot_shiro.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
public User findUser(User user);
}
service.java
package com.jiang.springboot_shiro.service;
import com.jiang.springboot_shiro.entity.User;
import com.jiang.springboot_shiro.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User findUser(User user){
return userMapper.findUser(user);
}
}
controller.java
这里有要注意的地方,在前面搭建springboot框架的时候注释是@RestController,这里要访问页面,要把注释改成@Controller
package com.jiang.springboot_shiro.controller;
import com.jiang.springboot_shiro.entity.User;
import com.jiang.springboot_shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class UserController {
/*@RequestMapping("springboot_shiro")//项目访问URL
public String index(){
return "Hello springboot!";
}*/
@Autowired
private UserService userService;
@RequestMapping("/")
public String getIndex(){
return "login";
}
@RequestMapping("all")
public String getAll(){
return "all";
}
@RequestMapping("one")
public String getOne(){
return "one";
}
@RequestMapping("login")
public String login(){
return "login";
}
@RequestMapping("permission")
public String permission(){
return "permission";
}
@RequestMapping("toLogin")
public String toLogin(User user, Model model){
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken userToken=new UsernamePasswordToken(user.getName(),user.getPassword());
try{
subject.login(userToken);
return "redirect:/all";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
}
HTML页面就不贴了,只有一个登陆表单,随便写个就行了
最重要的是shiro的配置,这里没有用配置文件,用了注解
shiroConfig.java
package com.jiang.springboot_shiro.shiro;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
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(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> fMap=new HashMap<>();
//拦截页面
fMap.put("/all","authc");
fMap.put("/one","authc");
//拦截未授权
fMap.put("/all","perms[user:all]");
fMap.put("/one","perms[user:one]");
//被拦截返回登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
//授权拦截返回页面
shiroFilterFactoryBean.setUnauthorizedUrl("/permission");
shiroFilterFactoryBean.setFilterChainDefinitionMap(fMap);
return shiroFilterFactoryBean;
}
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
}
@Bean(name = "userRealm")
public UserRealm getUserRealm(){
return new UserRealm();
}
}
配置文件里有一些拦截的配置,anon,authc等,这些还有点糊涂。
shiro最重要的还是Realm类,自定义UserRealm需要继承AuthorizingRealm类,并重写其中的doGetAuthenticationInfo方法和doGetAuthorizationInfo方法,其中在controller中调用subject.login(token)时最终是会调用doGetAuthenticationInfo(token)方法,当访问的页面需要鉴权的时候会调用doGetAuthorizationInfo(principle)方法。
我自定义的UserRealm.java
package com.jiang.springboot_shiro.shiro;
import com.jiang.springboot_shiro.entity.User;
import com.jiang.springboot_shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0){
System.out.println("授权");
Subject subject=SecurityUtils.getSubject();
User user=(User) subject.getPrincipal();
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermission(user.getAuthority());
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
// TODO Auto-generated method stub
System.out.println("认证");
//shiro判断逻辑
UsernamePasswordToken user = (UsernamePasswordToken) arg0;
User realUser = new User();
realUser.setName(user.getUsername());
realUser.setPassword(String.copyValueOf(user.getPassword()));
User newUser = userService.findUser(realUser);
//System.out.println(user.getUsername());
if(newUser == null){
//用户名错误
//shiro会抛出UnknownAccountException异常
return null;
}
return new SimpleAuthenticationInfo(newUser,newUser.getPassword(),"");
}
}
这个类还需要改正,因为这个认证的方法里,无论如何都只能返回UnknownAccountException异常,controller中永远都catch不到IncorrectCredentialsException,目前怎么更正我还没想好。
因为没有配置默认 访问路径,只要访问localhost:8080/就能访问该项目了,在我的控制器里面我后来又加上了下面这一段代码,如果没有这一段代码我直接访问返回的是404,但是这样程序已经跑起来了,如果输入localhost:8080/login会发现能够访问的。
@RequestMapping("/")
public String getIndex(){
return "login";
}
只是个测试,所以没写首页,直接访问登录页面了。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!