SpringSecurity学习(三)JDBC用户存储,注销登录

JDBC用户存储

依赖

<!--数据库连接-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

properties

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql:///spring_security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

建表

Spring Security默认情况下需要两张表,用户表和权限表

参考mysql

create table users(username varchar(50) not null primary key,password varchar(500) not null,enabled boolean not null);create table authorities (username varchar(50) not null,authority varchar(50) not null,constraint fk_authorities_users foreign key(username) references users(username));create unique index ix_auth_username on authorities (username,authority);

实现

@Resource
DataSource dataSource;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    JdbcUserDetailsManager manager = auth.jdbcAuthentication()
            .dataSource(dataSource)
            .getUserDetailsService();

    if (manager.userExists("zhow")) {
        System.out.println("已注册");
    } else {
        manager.createUser(User.withUsername("zhow")
                .password(new BCryptPasswordEncoder().encode("123"))
                .roles("admin")
                .build()
        );
    }
}

或者

@Resource
DataSource dataSource;

@Bean
public UserDetailsService userDetailsService() {
   
    JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
    if (manager.userExists("zhow")) {
        System.out.println("已注册");
    } else {
        manager.createUser(User.withUsername("zhow")
                .password(new BCryptPasswordEncoder().encode("123"))
                .roles("admin")
                .build()
        );
    }
    return manager;
}

查询用户

自定义用户登录查询

新建一个service实现UserDetailsService接口

@Service
public class UserService implements UserDetailsService {


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 模拟数据库查询
        System.out.println("开始查询数据源。。。");

        if("zhow".equals(username)) {
            return User.withUsername("zhow")
                    .password(new BCryptPasswordEncoder().encode("123"))
                    .roles("admin")
                    .build();
        }else {
            throw new BadCredentialsException("没了");
        }
    }
}

自定义用户权限校验

校验器
public class MyAuthprovider implements AuthenticationProvider {
    
    //@Resource
    //注入不进去
    private UserService userService;

    public MyAuthprovider(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 密码校验

        System.out.println("开始自定义验证~~~~");
        System.out.println(authentication);

        //查询用户名
        UserDetails userDetails = userService.loadUserByUsername("xxx");

        // 密码加密器
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        // 密码加密
        String encodePass = passwordEncoder.encode(authentication.getCredentials().toString());

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, encodePass, userDetails.getAuthorities());

        return authenticationToken;
    }



    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

配置校验器

auth.authenticationProvider(new MyAuthprovider(userService));

这里有一个大坑,UserService 在MyAuthprovider中注入不进去,希望有知道原因的大神告诉一下我原因,万分感谢!
在这里插入图片描述

我使用在connfig中注入,通过构造方法去传到校验器中中。

同一用户多地点登录

踢掉其他已登录的用户

		http.
		// 哪些 地址需要登录
		authorizeRequests()
		//所有请求都需要验证
		.anyRequest().authenticated()
		.and()
		.formLogin()
		.and()
		.csrf().disable()
		.sessionManagement()
		.maximumSessions(1);

禁止其他终端登录

		http.
		// 哪些 地址需要登录
		authorizeRequests()
		//所有请求都需要验证
		.anyRequest().authenticated()
		.and()	
		.formLogin()	
		.and()	
		.csrf().disable()
		.sessionManagement()	
		.maximumSessions(1)	
		.maxSessionsPreventsLogin(true)

注销登录

开启CSRF之后 需要使用post请求退出接口
<a href="/logout">GET logout</a>
<br />
<form action="/logout" method="post">
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
    <input type="submit" value="POST Logout"/>
</form>
默认方式 get /logout
自定义url
	.and()
	.logout()
	.logoutUrl("/out")

增加退出处理器

		  http.logout().logoutUrl("/logout")
                .addLogoutHandler((request, response, authentication) -> {
                    // TODO Auto-generated method stub
                    System.out.println("退出1");
                })

                .addLogoutHandler((request, response, authentication) -> {
                    // TODO Auto-generated method stub
                    System.out.println("退出2");
                });

登录成功处理器

不同角色 跳转到不同页面

	.successHandler((request, response, authentication)-> {System.out.println("登录成功1");
                    // 根据权限不同,跳转到不同页面
                    Enumeration<String> attributeNames = request.getSession().getAttributeNames();
                    while (true){
                        if (attributeNames.hasMoreElements()){
                            System.out.println( request.getSession().getAttribute(attributeNames.nextElement()));
                        }else {
                            break;
                        }
                    }
                    request.getRequestDispatcher("").forward(request, response);
                });

其中 Authentication 参数包含了 用户权限信息

登录失败处理器

	.failureHandler((httpServletRequest, httpServletResponse, e)-> {
                        e.printStackTrace();
         })

可以限制登录错误次数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值