开始进行实际的Security的代码编写。
Security官方文档
过滤器链:
目前已有的,后面再加也是加在绿色的过滤器链位置。
建表(用户表,用于登录)
CREATE TABLE `account` (
`id` varchar(32) NOT NULL COMMENT '主键,UUID编码',
`user_name` varchar(11) DEFAULT NULL COMMENT '用户名(手机号)',
`password` varchar(64) DEFAULT NULL COMMENT '密码',
`num` int(1) DEFAULT NULL COMMENT '登陆失败次数(5)',
`locked` tinyint(1) DEFAULT '1' COMMENT '是否锁定,默认未锁定,0-锁定',
`enabled` tinyint(1) DEFAULT '1' COMMENT '是否可用,默认可用,0-被删',
`expired` tinyint(1) DEFAULT '1' COMMENT '是否过期,true未过期,false过期',
`role` varchar(50) DEFAULT NULL COMMENT '角色',
`state` char(1) NOT NULL COMMENT '状态值,是否可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
注意,user_name字段需要建立索引,否则如果因为某些原因存在两个相同的手机号登录会失败。可以适当地加一些注册时间,修改时间等字段,此表仅作为最初版。使用mybatis-generator自动生成代码。
数据库默认数据:
自定义实现类实现UserDetailsService接口:
package com.cong.security.service.impl;
import com.cong.security.entity.Account;
import com.cong.security.mapper.AccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
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;
/**
* @Description 自定义用户名密码登录
* @Author single-聪
* @Date 2020/1/7 18:42
* @Version 1.0.1
**/
@Slf4j
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private AccountMapper accountMapper;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
// 查询用户信息
Account account = accountMapper.loginByPhone(name);
log.info("当前登录账户为:[{}]...账户信息为:[{}]", name, account);
// 需要考虑到account查询为null的情况
// 用户名,密码,账户状态,权限
return new User(name, account.getPassword(), account.getEnabled(), account.getExpired(), true,
account.getLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList(account.getRole()));
}
}
注意需要整合MyBatis,无非是相关jar包以及一点点配置,本文不赘述。
现在访问任一接口localhost:8001/login/hello
,输入18888888888密码123456之后后端报错:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
进入文章开头Security文档,搜索PasswordEncoder
,6.9认证章节介绍了解决办法,内存身份验证,JDBC身份认证(采用默认的密码加解密方式),本文使用最后一种解决方式:注入bean:
package com.cong.security.browser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Description TODO
* @Author single-聪
* @Date 2020/1/7 18:00
* @Version 1.0.1
**/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 使用表单登录进行身份认证
http.formLogin()
.and()
.authorizeRequests()
.anyRequest() // 任何请求
.authenticated(); // 需要身份认证
super.configure(http);
}
}
此时启动项目访问之后报错:Authentication request failed: org.springframework.security.authentication.BadCredentialsException: 用户名或密码错误
,密码匹配失败,所以我们需要先对一个密码进行加密存储仅数据库中,123456对应的加密后的密码为:$2a$10$ccYrukNANQs9FAMcGfivBOpXU5KI/SGgpUUyOn2iL7FugEyG97ss6
,自己加密一次即可,每次结果不一样,现在在调用登录接口输入18888888888和123456即可登陆成功并成功调用指定接口获得返回值。