Spring Security查询数据库实现登录(springboot+mybatis) 作者:马育民 • 2020-08-03 16:23 • 阅读:10116 # 概述 本文通过springboot+security+mybatis实现 关于springboot集成mybatis,详见: [springboot整合mybatis(配置文件)](https://www.malaoshi.top/show_1EF5gW27Vba9.html "springboot整合mybatis(配置文件)") # 原理 不需要实现Controller,servlet等,接收登录请求功能,(获取用户、密码),security自身实现 需要实现登录service 需要实现用户封装类 # 页面 ``` Title 用户名: 密码: ``` # 用户表结构 ``` -- auto-generated definition create table user ( id varchar(32) not null primary key, nickname varchar(32) default '' not null, password varchar(64) default '' not null, role varchar(32) null, username varchar(32) not null ) collate = utf8mb4_unicode_ci; ``` ### 记录 一条记录: ``` id:1 nickname:超级管理员 password:123456 role:admin username:admin ``` # 实现配置类 ``` package top.malaoshi.stdsecurity.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.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import top.malaoshi.stdsecurity.security.SLoginService; import javax.annotation.Resource; @Configuration @EnableWebSecurity //@EnableGlobalMethodSecurity(securedEnabled=true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 指定密码编码器,当前密码为明文 @Bean public PasswordEncoder passwordEncoder(){ // return new BCryptPasswordEncoder(); return NoOpPasswordEncoder.getInstance(); } // 登录service,自定义实现 @Resource private SLoginService sLoginService; // 指定使用自定义的登录service,并指定密码编码器 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(sLoginService).passwordEncoder(passwordEncoder()); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**","/js/**","/img/**");//绕开所有的filter,直接跳过验证 } // 安全拦截机制 @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .authorizeRequests()//url权限配置 // .antMatchers("/index.html").permitAll() // 匹配这些路径可以所有人访问 .antMatchers("/dept/**").hasRole("admin") .antMatchers("/user/**").hasRole("admin") .anyRequest().authenticated() .and() //login部分 .formLogin() .loginPage("/login.html")//指定登录页面。所有url前面必须写/,否则报错 'xxx' is not a valid forward URL // .usernameParameter("user")//登录页面用户名控件name值 // .passwordParameter("pwd")//登录页面密码控件name值 .loginProcessingUrl("/login")//security提供的处理登录url,默认是/login // .successForwardUrl("/index.html")//登录成功后跳转的页面,需要额外处理才能使用,否则页面会提示错误 .defaultSuccessUrl("/index.html")//登录成功后重定向的页面 .failureUrl("/login_fails.html")//登录失败跳转的页面 // .failureForwardUrl("/login_fails.html")//登录失败不会转发 .permitAll()//让login部分的url可以任意访问 // // //logout部分 .and() .logout()//退出登录需要提交post请求 .logoutSuccessUrl("/login.html")//退出成功访问的页面 .invalidateHttpSession(true)//清空session .permitAll();//让logout部分的url可以任意访问 } } ``` 关键部分: - 这里使用了角色判断`.hasRole("admin")`,此处admin没有前缀`ROLE_`,在登录service,要做前缀处理 - 如果登录页面用户名控件的name值不是`username`,要通过`.usernameParameter("user")`指定 - 如果登录页面密码控件的name值不是`password`,要通过`.passwordParameter ("pwd ")`指定 # 实现登录用户封装类 之前文章用的是security框架内置的`User`类,该类也是实现`UserDetails`接口,该类的属性较少,所以这里重新实现,增加`id`、`nickname`等属性 ``` package top.malaoshi.stdsecurity.security; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class SUser implements UserDetails { private String id; private String nickname; private String username; private String password; private List authorities=new ArrayList<>(); public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public void setUsername(String username) { this.username = username; } public String getId() { return id; } public void setId(String id) { this.id = id; } public void setPassword(String password) { this.password = password; } public void setAuthorities(List authorities) { this.authorities = authorities; } @Override public Collection extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } //账户是否未过期,过期无法验证 @Override public boolean isAccountNonExpired() { return true; } //用户是否解锁,锁定的用户无法进行身份验证 @Override public boolean isAccountNonLocked() { return true; } //用户的凭据(密码),是否已过期,过期的凭据不能认证 @Override public boolean isCredentialsNonExpired() { return true; } //是否可用 ,禁用的用户不能身份验证 @Override public boolean isEnabled() { return true; } } ``` # 实现登录service ``` package top.malaoshi.stdsecurity.security; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import top.malaoshi.stdsecurity.mapper.UserMapper; import javax.annotation.Resource; @Service public class SLoginService implements UserDetailsService { @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { top.malaoshi.stdsecurity.entity.User user=userMapper.getUserByUsername(username); SUser sUser=new SUser(); org.springframework.beans.BeanUtils.copyProperties(user, sUser); sUser.setAuthorities(AuthorityUtils.createAuthorityList("ROLE_"+user.getRole())); return sUser; } } ``` 将数据库查询出的对象的属性,拷贝到`SUser`对象中,然后再加上权限、角色 **注意** :在角色的前面加上前缀`ROLE_`,这样在配置类中才能使用`.hasRole("admin")` # 测试 访问并登录 同类好文: https://www.cnblogs.com/ealenxie/p/9293768.html 原文出处:http://malaoshi.top/show_1EF60TiZbUtW.html