Spring Security(Mysql)

2019-11-17  本文已影响0人  凌康ACG

Spring Security基于Mysql身份验证(自定义认证,基于角色),由于业务的复杂性我们不可能使用spring官网的example来做认证,本次主要是重写security的认证方式,阅读源码即可实现。
下一篇为Spring Security自定义授权:
技术栈:
springboot+springsecurity+mybatis所用最新框架spring5,2019年11月17日 14:51:16
项目基于上一篇文章springsecurity内存认证授权https://www.jianshu.com/p/d71c7fa9b534

一、首先创建项目springsecurity-mysql

image.png
image.png
页面基于上篇文章:https://www.jianshu.com/p/d71c7fa9b534
maven如下
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lingkang</groupId>
    <artifactId>springsecurity-mysql</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springsecurity-mysql</name>
    <description>2019年11月17日 15:32:40</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--html页面使用sec标签,属于spring5 security-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

        <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>2.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

创建数据库名称为security和两张表:用户表(se_user)、角色表(se_role):

DROP TABLE IF EXISTS `se_role`;
CREATE TABLE `se_role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NULL DEFAULT NULL,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  `update_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of se_role
-- ----------------------------
INSERT INTO `se_role` VALUES (1, 1, 'vip1', '2019-11-17 15:27:04', NULL);
INSERT INTO `se_role` VALUES (3, 2, 'vip2', '2019-11-17 15:27:26', NULL);
INSERT INTO `se_role` VALUES (4, 2, 'vip3', '2019-11-17 15:27:35', NULL);
INSERT INTO `se_role` VALUES (5, 3, 'vip1', '2019-11-17 15:28:00', NULL);
INSERT INTO `se_role` VALUES (6, 3, 'vip2', '2019-11-17 15:28:08', NULL);
INSERT INTO `se_role` VALUES (7, 3, 'vip3', '2019-11-17 15:28:16', NULL);

-- ----------------------------
-- Table structure for se_user
-- ----------------------------
DROP TABLE IF EXISTS `se_user`;
CREATE TABLE `se_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `status` int(1) NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  `update_titme` datetime(0) 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 se_user
-- ----------------------------
INSERT INTO `se_user` VALUES (1, '张三', '123', '123', 1, '2019-11-17 15:26:10', NULL);
INSERT INTO `se_user` VALUES (2, '李四', 'user', '123', 1, '2019-11-17 15:26:28', NULL);
INSERT INTO `se_user` VALUES (3, '管理员', 'admin', 'admin', 1, '2019-11-17 15:26:46', NULL);

application.properties配置如下:

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/security?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

#配置xml扫描
mybatis.mapper-locations=classpath:mapper/*.xml

搭建项目如下


image.png

二、修改代码

创建自定义CustomUserDetailsServiceImpl :

@Component //交给spring托管,应为我们使用@Autowired注入了spring的接口
public class CustomUserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //查询用户
        SeUser user = userService.getUserInfo(s);
        if (user == null) {
            throw new UsernameNotFoundException("帐号:" + s + " 不存在!");
        }
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        //查询拥有的角色
        List<SeRole> roles = userService.getUserRoleByUserId(user.getId());
        roles.forEach(r -> {
            //security的验证规则需要ROLE_,由于我数据库是vip1、vip2、vip3这种值,需要加上ROLE_
            grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + r.getName()));
        });
        //spring5+要求密码加密,我这里传明文密码来加密
        String password = new BCryptPasswordEncoder().encode(user.getPassword());
        return new User(user.getUsername(), password, grantedAuthorities);
    }

}

修改SecurityConfig:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //注入我们加密的方式,spring5+以上必须要加密密码,这是官网推荐的加密方式,也可选择MD5
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //由于我们自定义了UserDetailsService,我们需要新注入这个bean
    @Bean
    @Override //重写
    public UserDetailsService userDetailsServiceBean() {
        //使用我们自定义的 UserDetailsService
        return new CustomUserDetailsServiceImpl();
    }

    //认证----自定义认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //自定义认证
        auth.userDetailsService(userDetailsServiceBean());
    }

    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权规则,除了要授权的,其他所有人能访问
        http.authorizeRequests()
                .antMatchers("/vip1/**").hasAnyRole("vip1")
                .antMatchers("/vip2/**").hasAnyRole("vip2")
                .antMatchers("/vip3/**").hasAnyRole("vip3")
                .anyRequest().permitAll(); //其他页面所有人能访问

        //启动登陆页面
        //定制登陆页面,表单提交的路径loginProcessingUrl
        http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");

        //注销功能 ,跳回首页
        //关闭跨域认证请求,否则你需要post来注销
        http.logout().logoutSuccessUrl("/")
                .and().csrf().disable();

        //开启记住我功能,表单提交remember的参数
        http.rememberMe().rememberMeParameter("remember");
    }
}

项目总体如下:


image.png

三、效果如下:

登录123时:


image.png

登录user时:


image.png
登录admin时:
image.png

想要从session中获取用户信息可以:

SecurityContextImpl securityContextImpl = (SecurityContextImpl) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");

一般spring security在认证后,security会把一个SecurityContextImpl对象存储到session中,此对象中有当前用户的各种资料。
项目源码:https://github.com/xcocean/springsecurity-mysql

上一篇 下一篇

猜你喜欢

热点阅读