在处理Spring安全框架时,通常可以选择Shiro或者Security,做认证授权加密等。
推荐非SpringBoot,使用Shiro,SpringBoot项目使用Security
学习网址:
Security
Shiro
基础步骤:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
重启SpringBoot项目,访问网页,这里使用后台提供的账号密码登录
这里开始账号,密码,角色认证(对应User中参数)
@Service
public class DetailService implements UserDetailsService {
@Autowired
private PasswordEncoder pe;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new User("xiaoming",pe.encode("666"),new ArrayList<>());
}
}
这里使用PasswordEncoder做密码加密
这里使用加密算法BCryptPasswordEncoder
其他加密算法:
BCryptPasswordEncoder
Argon2PasswordEncoder
Pbkdf2PasswordEncoder
SCryptPasswordEncoder(单向加密)
加密器详细
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
密码必须加密,否则提示Encoded password does not look like BCrypt
必须包含账号密码角色
注意:由于UserDetailsService返回类型为UserDetails,因此创建的实体类需要实现UserDetails接口
实现UserDetails类重写以下方法。
private Integer id;
private String username;
private String password;
private String realName;
private Boolean enabled;
private Boolean locked;
private Boolean expired;
private Boolean credentialsExpired;
private Date createTime;
private Date loginTime;
//账号是否过期,0-已过期,1-未过期
@Override
public boolean isAccountNonExpired() {
return this.expired;
}
//账号是否被锁定,0-锁定,1-未锁定
@Override
public boolean isAccountNonLocked() {
return this.locked;
}
//账号凭证是否过期,0-已过期,1-未过期
@Override
public boolean isCredentialsNonExpired() {
return this.credentialsExpired;
}
//账号是否有效,0-失效,1-有效
@Override
public boolean isEnabled() {
return this.enabled;
}
//Collection authorities,这个属性中存储了这个用户所有的权限
//暂未使用,后面授权补充
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
重写的方法可以用做封号处理等
直接找数据库要信息就可以了
@Service
public class DetailService implements UserDetailsService {
@Autowired
private PasswordEncoder pe;
@Autowired
private SysUserDao sysUserDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserDao.selectByUsername(username);
return sysUser;
}
}
注意数据库中密码也必须是PasswordEncoder (使用同样的加密方式)加密过的
前面Security默认将所有URL拦截掉,需要登录认证才能访问URL下面我们把将公开的URL开放供所有人访问
- 控制Spring Security是否使用调试模式(通过注解属性debug指定),缺省为false,表示缺省不使用调试模式;
- 导入 WebSecurityConfiguration,用于配置Web安全过滤器FilterChainProxy;
- 如果是Servlet 环境,导入WebMvcSecurityConfiguration;
- 如果是OAuth2环境,导入OAuth2ClientConfiguration;
- 使用注解@EnableGlobalAuthentication启用全局认证机制;
重写
configure(HttpSecurity http)
先观察原本的configure(HttpSecurity http) 方法如下。
重写放权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/hello").permitAll()//所有人可以访问
.anyRequest().authenticated();//配置所有路径只有登录才可以访问
http.formLogin();//开启表单登录
http.httpBasic();
}
到这里已经成功放行了
下面简单记录一下几种主要配置
URL匹配常用的几种方式
- requestMatchers() 配置一个request Mather数组,参数为RequestMatcher 对象,其match 规则自定义,需要的时候放在最前面,对需要匹配的的规则进行自定义与过滤
- antMatchers() 配置一个request Mather 的 string数组,参数为 ant 路径格式, 直接匹配url
- anyRequest 匹配任意url,无参,必须放在最后面
URL权限
permitAll() 已登录和未登录用户都能访问
authenticated() 已登录用户能访问,未登录用户不能访问
anonymous() 未登录用户能访问,已登录用户不能访问
denyAll() 已登录和未登录用户都不能访问
rememberMe() 通过“记住我”功能直接登录的用户可以访问
fullyAuthenticated() 不是通过“记住我”功能直接登录的用户可以访问
登录login配置
1.formLogin() 配置基于表单登录的认证方式
loginPage() 登录页地址,默认“/login”
loginProcessingUrl 提交表单之后真正处理登录请求的地址
defaultSuccessUrl 默认跳转到 Referer 来源页面,如果 Referer 为空,没有来源页,则跳转到默认设置的页面
successForwardUrl 登录后一律跳转到指定的地址
failuerUrl登录失败之后系统转向的url,默认是loginPage + “?error”
failuerHandler登录失败之后的处理器
successHandler登录成功之后的处理器
2.httpBasic() 配置Http Basic认证方式
了解httpBasic
登出logout配置
logout() 配置登出
logoutUrl 登出url,默认是/logout
logoutSuccessUrl 登出成功后跳转的 url 默认是"/login?logout"
logoutSuccessHandler 登出成功处理器,设置后会把logoutSuccessUrl 置为null
如果这里运行访问http://localhost:8080/myLogin.html后台不报错,但是网页报
*This application has no explicit mapping for /error, so you are seeing this as a fallback. Mon May 09 17:03:35 CST 2022 There was an unexpected error (type=Not Found, status=404). No message available*
不必惊慌,有可能原因是:
这个功能主要是做网页登录记住我选项达到未来一段时间不用登录的效果。
以下代码都添加在SecurityConfig配置类中。
@Autowired
private DataSource dataSource; //数据库连接池
@Bean
public PersistentTokenRepository persistentTokenRepositoryBean(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
//指定数据源
jdbcTokenRepository.setDataSource(dataSource);
//启动时创建表,第一次启动时使用,后面要注释掉
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
如果我们运行第二次 而jdbcTokenRepository.setCreateTableOnStartup(true);没有注释那么后台报
Error creating bean with name ‘springSecurityFilterChain’ defined in class path resource …nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table ‘persistent_logins’ already exists,意思是这个存放记住我的相关表已经创建过了。
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
http.rememberMe().tokenRepository(persistentTokenRepositoryBean()).tokenValiditySeconds(10*24*60*60);
到这里Spring Security认证部分已经基本上是完了。
提一句一般用JWT替换httpBasic,只需要Spring Security整合JWT就可以了。