> 文档中心 > SpringSecurity简单教程(源码开源免费提供)

SpringSecurity简单教程(源码开源免费提供)


SpringSecurity菜鸟教程

一:简单配置权限管理

SecurityConfg的配置

package com.example.demo11.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.builders.WebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.password.PasswordEncoder;import java.util.Objects;@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Bean    public PasswordEncoder passwordEncoder() { return new PasswordEncoder() {     @Override     public String encode(CharSequence charSequence) {  return charSequence.toString();     }     @Override     public boolean matches(CharSequence charSequence, String s) {  return Objects.equals(charSequence.toString(), s);     } };    }    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("用户").password("123").roles("vip1")  .and()  .withUser("管理员").password("123").roles("vip2")  .and()  .withUser("超级管理员").password("123").roles("vip1", "vip2");    }    //配置忽略掉的 URL 地址,一般用于js,css,图片等静态资源    @Override    public void configure(WebSecurity web) throws Exception { //web.ignoring() 用来配置忽略掉的 URL 地址,一般用于静态文件 web.ignoring().antMatchers("/js/**", "/css/**", "/fonts/**", "/images/**", "/lib/**");    }    @Override    protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/css/**", "/js/**", "/images/**").permitAll(); //开启运行iframe嵌套页面 http.headers().frameOptions().disable(); http.authorizeRequests()  .antMatchers("/level1/vip1").hasRole("vip1")  .antMatchers("/level2/vip2").hasRole("vip2"); //没有权限会到默认的登录页面 http.formLogin();    }}

IndexController的代码

package com.example.demo11.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;@Controllerpublic class IndexController {    @GetMapping("/index")    public String index(){ return "index";    }    @GetMapping("/level1/vip1")    public String level1Vip1(){ return "level1/vip1";    }    @GetMapping("/level2/vip2")    public String level2Vip1(){ return "level2/vip2";    }}

由于没有设置springsecurity全部拦截,主页可以允许所有人访问
在这里插入图片描述

二:自定义登录页面,记住密码

1自定义登陆页面
改变SecurityConfig中的配置
这个需要自己写一个登录的接口

 @Override    protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/css/**", "/js/**", "/images/**").permitAll(); //开启运行iframe嵌套页面 http.headers().frameOptions().disable(); http.authorizeRequests()  .antMatchers("/level1/vip1").hasRole("vip1")  .antMatchers("/level2/vip2").hasRole("vip2"); //任何请求都必须经过身份认证 http.authorizeRequests().anyRequest().authenticated(); //没有权限会到默认的登录页面 http.formLogin()  //登录的页面  .loginPage("/login")  .usernameParameter("username")//自定义表单的用户名的name,默认为username  .passwordParameter("password")//自定义表单的密码的name,默认为password  .loginProcessingUrl("/dologin")//表单请求的地址,一般与form的action属性一致,注意:不用自己写doLogin接口,只要与form的action属性一致即可  .successForwardUrl("/index")//登录成功后跳转的页面(重定向)  .failureForwardUrl("/login")//登录失败后跳转的页面(重定向)  .and()  .logout() //开启注销功能  .logoutSuccessUrl("/login") //注销后跳转到哪一个页面  .clearAuthentication(true)// 配置注销登录请求URL为"/logout"(默认也就是 /logout)  .clearAuthentication(true) // 清除身份认证信息  .invalidateHttpSession(true) //使Http会话无效  .permitAll()  .and().csrf().disable();    }
login.html文件

在这里插入图片描述

2.记住密码和注销功能

 //开启记住我功能,cookie接收,默认保存两周,自定义接收其前端 http.rememberMe().rememberMeParameter("remember");

在这里插入图片描述
注销功能:
在这里插入图片描述

三:基于数据库自定义的表单验证

1.数据库表
这里的登录认证只涉及到三张表:用户表(user)、角色表(role)、用户角色中间表(user_role)。

/* Navicat Premium Data Transfer Source Server  : test3 Source Server Type    : MySQL Source Server Version : 80015 Source Host    : localhost:3306 Source Schema  : test2 Target Server Type    : MySQL Target Server Version : 80015 File Encoding  : 65001 Date: 31/05/2020 22:01:56*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for role-- ----------------------------DROP TABLE IF EXISTS `role`;CREATE TABLE `role`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Records of role-- ----------------------------INSERT INTO `role` VALUES (1, 'ROLE_vip0');INSERT INTO `role` VALUES (2, 'ROLE_vip1');INSERT INTO `role` VALUES (3, 'ROLE_vip2');INSERT INTO `role` VALUES (4, 'ROLE_vip3');-- ------------------------------ Table structure for user-- ----------------------------DROP TABLE IF EXISTS `user`;CREATE TABLE `user`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `username` varchar(32) 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 (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Records of user-- ----------------------------INSERT INTO `user` VALUES (1, 'root', '$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq');INSERT INTO `user` VALUES (3, '灰太狼', '$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq');INSERT INTO `user` VALUES (4, '喜羊羊', '$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq');INSERT INTO `user` VALUES (5, '懒羊羊', '$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq');INSERT INTO `user` VALUES (6, '小灰灰', '$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq');-- ------------------------------ Table structure for user_role-- ----------------------------DROP TABLE IF EXISTS `user_role`;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 = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Records of user_role-- ----------------------------INSERT INTO `user_role` VALUES (1, 1, 1);INSERT INTO `user_role` VALUES (2, 1, 2);INSERT INTO `user_role` VALUES (3, 1, 3);INSERT INTO `user_role` VALUES (4, 1, 4);INSERT INTO `user_role` VALUES (5, 3, 2);INSERT INTO `user_role` VALUES (6, 4, 3);INSERT INTO `user_role` VALUES (7, 6, 4);INSERT INTO `user_role` VALUES (8, 5, 1);SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述

注意:这里的role跟上面的例子相比多加了ROLE_前缀。这是因为之前的role都是通过springsecurity的api赋值过去的,他会自行帮我们加上这个前缀。但是现在我们使用的是自己的数据库里面读取出来的权限,然后封装到自己的实体类中。所以这时候需要我们自己手动添加这个ROLE_前缀。经过测试如果不加ROLE_前缀的话,可以做数据库的认证,但无法做授权

2.建实体类User,注意User需要实现UserDetails接口,并且实现该接口下的7个接口

package com.example.demo11.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList;import java.util.Collection;import java.util.List;@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements UserDetails {    private Integer id;    private String userName;    private String passWord;    private List<Role> roles;//该用户对应的角色    /**     * 返回用户的权限集合。     * @return     */    @Override    public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role : roles){     authorities.add(new SimpleGrantedAuthority(role.getName()));     System.out.println(authorities); } return authorities;    }    /**     * 返回账号的密码     * @return     */    @Override    public String getPassword() { return passWord;    }    /**     * 返回账号的用户名     * @return     */    @Override    public String getUsername() { return userName;    }    /**     * 账号是否失效,true:账号有效,false账号失效。     * @return     */    @Override    public boolean isAccountNonExpired() { return true;    }    /**     * 账号是否被锁,true:账号没被锁,可用;false:账号被锁,不可用     * @return     */    @Override    public boolean isAccountNonLocked() { return true;    }    /**     * 账号认证是否过期,true:没过期,可用;false:过期,不可用     * @return     */    @Override    public boolean isCredentialsNonExpired() { return true;    }    /**     * 账号是否可用,true:可用,false:不可用     * @return     */    @Override    public boolean isEnabled() { return true;    }}

角色表实体类Role,这个类不用实现上述接口

package com.zsc.po;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructorpublic class Role {    private Integer id;    private String name;//角色的名字}

接下来做数据库的查询,创建持久层接口(UserMapper和RoleMapper)

package com.example.demo.mapper;import com.example.demo.pojo.Role;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;import java.util.List;@Mapper@Repositorypublic interface RoleMapper {    /**     * 通过用户id获取用户角色集合     *     * @param userId 用户id     * @return List 角色集合     */    List<Role> getRolesByUserId(Integer userId);}
package com.example.demo.mapper;import com.example.demo.pojo.User;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;import java.util.List;@Mapper@Repositorypublic interface UserMapper {    /**     * 通过用户名获取用户信息     *     * @param username 用户名     * @return User 用户信息     */    List<User> getUserByUsername(String username);}

持久层接口对应配置文件(UserMapper.xml和RoleMapper.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.example.demo.mapper.RoleMapper">    <resultMap id="roleMap" type="com.example.demo.pojo.Role"> <id column="id" property="id"></id> <result column="name" property="name"></result>    </resultMap>    <select id="getRolesByUserId" resultMap="roleMap"> select * from role r,user_role ur where r.id = ur.rid and ur.uid = #{userId}    </select></mapper>
<?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.example.demo.mapper.UserMapper">    <resultMap id="userMap" type="com.example.demo.pojo.User"> <id column="id" property="id"></id> <result column="username" property="userName"></result> <result column="password" property="passWord"></result> <collection property="roles" ofType="com.example.demo.pojo.Role">     <id property="id" column="rid"></id>     <result column="rname" property="name"></result> </collection>    </resultMap>    <select id="getUserByUsername" resultMap="userMap"> select * from user  where username = #{username}    </select></mapper>

源码地址:SpringSecurity