springboot整合springsecurity

1、创建需要的数据库
1.1用户表

CREATE TABLE user ( 
uid int(11) NOT NULL AUTO_INCREMENT,
username varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 
password varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 
PRIMARY KEY (uid) USING
BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8
COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

1.2权限表

CREATE TABLE role ( 
rid int(11) NOT NULL AUTO_INCREMENT,
role varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 
PRIMARY KEY (rid) USING BTREE ) ENGINE = InnoDB
AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci
ROW_FORMAT = Dynamic;

1.3关系表

CREATE TABLE user_role ( 
id int(11) NOT NULL AUTO_INCREMENT,
uid int(11) NULL DEFAULT NULL, rid int(11) NULL DEFAULT NULL,
PRIMARY KEY (id) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 10
CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

1.4添加测试数据

-- 添加2个用户 
INSERT INTO user VALUES (1, 'user', 'e10adc3949ba59abbe56e057f20f883e');
INSERT INTO user VALUES (2, 'admin', 'e10adc3949ba59abbe56e057f20f883e');
-- 添加2个角色 
INSERT INTO role VALUES (1, 'user'); 
INSERT INTO role VALUES (2, 'admin');

-- 2个用户,分别拥有1个角色 
INSERT INTO user_role VALUES (1, 1, 1); 
INSERT INTO user_role VALUES (2, 2, 2);

2、创建一个springboot项目,名字随便,然后在项目的pom.xml中添加如下有关依赖

	<dependencies>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--springboot-spring-security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

        <!--mybatis和springboot整合包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--数据源-->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>

        <!--jdbc驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--log4j-->
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</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>

        <resources>
            <!-- 配置将哪些资源文件(静态文件/模板文件/mapper文件)加载到tomcat输出目录里 -->
                <resource>
                    <!--java文件的路径-->
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                    <!-- <filtering>false</filtering>-->
                </resource>
                <resource>
                    <directory>src/main/resources</directory><!--资源文件的路径-->
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                    <!-- <filtering>false</filtering>-->
                </resource>
        </resources>

    </build>

3、创建项目结构包
在这里插入图片描述
4、在application-db.yml配置数据源

spring:
  datasource:
    username: root
    password: 123456
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

5、在application.properties做有关配置

#端口
server.port=8081

#添加application-db.yml
spring.profiles.active=db

#为实体类设置别名
mybatis.type-aliases-package=com.itlhc.pojo

#绑定mapper.xml
mybatis.mapper-locations=com/itlhc/dao/*.xml

6、在dao包下创建UserMapper接口和UserMapper.xml配置文件

@Mapper
@Repository
public interface UserMapper {
    //添加用户
    @Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
    int insertUser(User user);
    //添加用户权限
    @Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
    Integer insertsqx(User qx);
    //查询全部用户
    List<User> selectUser();
    //根据用户名字查询用户
    UserDTO selectUserByUsername(@Param("username") String username);
    //根据用户名查id
    User selectUsername(User user);
}
<?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.itlhc.dao.UserMapper">

	<resultMap id="userRoleMap" type="com.itlhc.pojo.UserDTO">
        <id property="uid" column="uid"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <collection property="roles" ofType="com.itlhc.pojo.RoleDTO">
            <id property="rid" column="rid"/>
            <result property="role" column="role"></result>
        </collection>
    </resultMap>
    
    <!--增加用户-->
    <insert id="insertUser" parameterType="User">
        insert into user(username,password)values(#{username},#{password});
    </insert>

    <!--添加用户权限-->
    <select id="insertsqx" parameterType="User">
        insert into user_role(id,uid,rid)values (#{id},#{uid},2);
    </select>

    <!--根据用户名查询id-->
    <select id="selectUsername" parameterType="User" resultType="User">
        select * from  user where username = #{username};
    </select>

    <!--查询全部用户-->
    <select id="selectUser" resultMap="userRoleMap">
        select uid,username,password from user;
    </select>

    <!--验证用户密码和查询用户权限-->
    <select id="selectUserByUsername" resultMap="userRoleMap">
        select user.uid, user.username, user.password, role.rid, role.role
        from user, user_role, role
        where user.username=#{username}
        and user.uid = user_role.uid
        and user_role.rid = role.rid
    </select>

</mapper>

7、在pojo包下创建如下实体类
7.1Role

//权限表映射
@Data
public class Role {
        private Integer rid;
        private String role;
}

7.2RoleDTO

//权限匹配
@Setter
@Getter
public class RoleDTO extends Role {
    private Set<Role> users;
}

7.3TestUser

//权限和密码认证
public class TestUser extends User {

    public TestUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

}

7.4User

//用户表映射
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private Integer id;//关系表id
    private Integer rid;//权限id
    private Integer uid;//用户id
    private String username;
    private String password;
}

7.5UserDTO

//用户信息以及权限匹配
@Setter
@Getter
public class UserDTO extends User {
    private Set<Role> roles;
}

8、在service中创建UserService接口和UserServiceImpl实现类,以及MyUserDetailsService身份认证类
8.1UserService

public interface UserService {

    //添加用户
    int insertUser(User user);
    //添加用户权限
    Integer insertsqx(User qx);
    //查询全部用户
    List<User> selectUser();
    //查询用户
    UserDTO selectUserByUsername(@Param("username") String username);
}

8.2UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int insertUser(User user) {
        //加密
        user.setUsername(user.getUsername());
        user.setPassword(MD5Util.pwdMd5(user.getPassword()));
        return userMapper.insertUser(user);
    }

    @Override
    public Integer insertsqx(User qx) {
        User user = userMapper.selectUsername(qx);
        Integer qxs = null;
        qxs = user.getUid();
        qx.setUid(qxs);
        userMapper.insertsqx(qx);
        System.out.println("qxs:"+qx);
        return null;
    }

    @Override
    public List<User> selectUser() {
        return userMapper.selectUser();
    }

    @Override
    public UserDTO selectUserByUsername(String username) {
        return userMapper.selectUserByUsername(username);
    }
}

8.3MyUserDetailsService

//身份认证类
@Component
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("username:"+username);
        UserDTO user = userService.selectUserByUsername(username);
        System.out.println("user:"+user);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        //添加用户拥有的多个角色
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRole()));
        }
        System.out.println("grantedAuthorities:"+grantedAuthorities);
        System.out.println("password:"+user.getPassword());

        //构造返回值
        TestUser testUser = new TestUser(user.getUsername(), user.getPassword(), grantedAuthorities);

        return testUser;
    }
}

9、在utils工具包下创建MD5Util加密类

/**
 * MD5加密解密工具类
 */
public class MD5Util {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 转换字节数组为16进制字串
     *
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     *
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }


    /**
     * 密码加密
     *
     * @param password
     * @return
     */
    public static String pwdMd5(String password) {
        String pwdMd5 = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(password.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            pwdMd5 = sb.toString().toLowerCase();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pwdMd5;
    }
}

10、在config包下创建SecurityConfig配置类

/**
 * 开启注解权限鉴定, securedEnabled: 开启@Secured注解(拥有某个角色可以访问);
 * prePostEnabled:开启@PreAuthorize注解(拥有某个角色或者某个权限可以访问,在方法执行之前校验)
 *                 开启@PostAuthorize注解(拥有某个角色或者某个权限可以访问,在方法执行之后校验)
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

     /**
     * 指定加密方式-->BCryptPasswordEncoder
     */
    /*@Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                // 从数据库读取的用户进行身份认证
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }*/


    /**
     * 指定加密方式-->MD5Util
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                //密码加密方法
                .passwordEncoder(new PasswordEncoder() {
                    //密码加密规则
                    @Override
                    public String encode(CharSequence charSequence) {
                        return MD5Util.pwdMd5((String) charSequence);
                    }

                    //密码校验规则
                    @Override
                    public boolean matches(CharSequence charSequence, String s) {
                        return encode(charSequence).equals(s);
                    }
                });
    }

    /*
        hasAuthority没ROLE_ 前缀,hasAnyRole有ROLE_ 前缀,是自动添加ROLE_前缀。
        authority 描述的的是一个具体的权限,例如针对某一项数据的查询或者删除权限,
        它是一个 permission,例如 read_employee、delete_employee、update_employee 之类的,这些都是具体的权限,相信大家都能理解。
        hasAnyRole在项目中,我们可以将用户和角色关联,角色和权限关联,权限和资源关联。
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //禁用跨域保护
        http.csrf().disable();
        //配置登出
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/LoginHtml").permitAll();
        http
                .formLogin()//自定义自己编写的登陆页面
                .loginPage("/LoginHtml") //登录页面设置
                .loginProcessingUrl("/user/login")//登录访问路劲(随便写)
                .defaultSuccessUrl("/index1").permitAll()//登录成功之后跳转的页面
                .and().authorizeRequests()
                .antMatchers("/", "/user/login", "/LoginHtml","/registerUser","/registers").permitAll()//哪些路径可以直接访问,不需要验证
                .antMatchers("/test2").hasAnyRole("user")//拥有该权限可以访问,hasAnyRole会自动添加ROLE_前缀
                .antMatchers("/test3").hasAnyRole("admin")
        ;
        //没有权限进行访问跳转的页面
        http.exceptionHandling().accessDeniedPage("/unauth");
    }
}

11、在controller包下创建LoginController登录控制类、RegisterController注册控制类、UserController用户控制类
11.1LoginController

@Controller
public class LoginController {

    @GetMapping("test2")
    @ResponseBody
    public String test2(){
        return "hello,test2";
    }

    @GetMapping("test3")
    @ResponseBody
    public String test3(){
        return "hello,test3";
    }

    @GetMapping("index1")
    public String index(){
        return "user/index1";
    }

    @RequestMapping("LoginHtml")
    public String loginHtml(){
        return "user/login";
    }

    @GetMapping("unauth")
    public String unauthHtml(){
        return "user/unauth";
    }

}

11.2RegisterController

@Controller
public class RegisterController {

    @Autowired
    private UserService userService;

    @RequestMapping("registers")
    public String registers(){
        return "user/register";
    }

    @RequestMapping("registerUser")
    public String register(User user){

        int i = userService.insertUser(user);
        userService.insertsqx(user);
        System.out.println("注册成功:"+i);

        return "user/login";
    }
}

11.3UserController

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/selectUser")
    @ResponseBody
    public List<User> selectUserList(){
        List<User> users = userService.selectUser();
        return users;
    }

}

12、html页面
12.1index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎来到lhc信息管理系统</h1>
<a th:href="@{/LoginHtml}">登录</a>
<a th:href="@{/registers}">注册</a>
</body>
</html>

12.2login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎登录!</h1>
<form th:action="@{/user/login}" th:method="post">
    <div class="form-group">
        <label for="username">Username</label>
        <input type="username" class="form-control" id="username" th:name="username" placeholder="username">
    </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input type="password" class="form-control" id="password" th:name="password" placeholder="password">
    </div>
    <button type="submit" class="btn btn-default">Submit</button>
</form>
</body>
</html>

12.3register.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎注册!</h1>
<form th:action="@{/registerUser}" th:method="post">
    <div class="form-group">
        <label for="username">Username</label>
        <input type="username" class="form-control" id="username" th:name="username" placeholder="username">
    </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input type="password" class="form-control" id="password" th:name="password" placeholder="password">
    </div>
    <button type="submit" class="btn btn-default">注册</button>
</form>
</body>
</html>

12.4index1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!--<input id="text" type="button" value="查询"/>-->
<!--<p>这是一个段落。</p>
<button>切换</button>-->
<div class="row clearfix">
    <div class="col-md-12 column">
        <table id = id="table" class="table table-hover table-striped">
            <thead>
            <tr>
                <th><input type="checkbox" id="checkAll" name="checkAll">全选</th>
                <th>uid</th>
                <th>username</th>
                <th>password</th>
                <th colspan="2">操作</th>
            </tr>
            </thead>

            <tbody id="tbodyId">
            <tr>

            </tr>
            </tbody>
        </table>
    </div>
</div>

<a th:href="@{/logout}">注销</a>
<a th:href="@{/test2}">test2</a>
<a th:href="@{/test3}">test3</a>
</body>

<script type="text/javascript" src="https://upcdn.b0.upaiyun.com/libs/jquery/jquery-2.0.2.min.js"></script>
<script type="text/javascript">
    /*$(document).ready(function(){
        $("button").click(function(){
            $("p").slideToggle();
        });
    });
*/

    $(document).ready(function(){
        /*$("#text").bind("click",function(){*/
            // 基于ajax技术向服务端发送异步请求, 获取数据, 然后更新到页面上
            // 1. 定义url
            var url = "selectUser";
            // 2. 请求参数
            // 3. 发送异步请求, 处理响应结果
            // 向服务器发送Get请求
            $.get(url, function(result) { // 用于处理结果
                // 获取tbody对象
                var tBody = $("#tbodyId");
                // 清空tbody的内容
                tBody.empty();
                // 迭代result对象, 将数据填充到tbody
                result.forEach(user => {
                    tBody.append(doCreateRow(user));
                });
            }, "json");

            // 创建一行数据
            function doCreateRow(user) {
                return `<tr>
                <td> <input type='checkbox' id="checkAll" name="checkAll" value=${user.uid}> </td>
                <td> ${user.uid} </td>
                <td> ${user.username} </td>
                <td> ${user.password} </td>
                <td>
                    <button type='button' class='btn btn-danger btn-sm' onclick='doDeleteById(${user.uid})'>update</button>
                    <button type='button' class='btn btn-danger btn-sm' onclick='doDeleteById(${user.uid})'>delete</button>
                </td>
            </tr>`;
            }
       /* });*/
    });

</script>
</html>

12.5error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>发生错误</h1>
</body>
</html>

12.6unauth.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>没有权限</h1>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值