发表于: 2020-07-24 22:55:00
1 1474
今天完成的事情:
1.使用SpringSecurity实现登录功能。
和用拦截器实现不同的是,使用SpringSecurity实现登录功能不需要我们手动写登录请求了。只需要在我们自己写的SecurityConfig配置类中加入:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/index.xml","/tologin","/login").permitAll()
.antMatchers("/u/**","/main").hasRole("account");
http.formLogin()
.loginPage("/tologin")
.loginProcessingUrl("/login");
//.usernameParameter("user").passwordParameter("psw");
}
默认接收到的前端页面参数是username和password,如果不是这两个的话可以用.usernameParameter()方法来指定参数。
2.使用SpringSecurity实现记住登录功能。
使用SpringSecurity来实现记住登录的功能也很简单,只需要加上http.remember即可,之前使用拦截器的话要写大量代码来判断,现在只需要这么一句就可以了。
http.rememberMe().rememberMeParameter("remember-me");
前端代码:
<input type="checkbox" name="remember-me">
Springboot会自动帮我们生成一个cookie:
3.使用SpringSecurity实现注销功能。
想实现注销功能也很方便,不用像以前一样写logout方法,只需要添加一句:
http.logout().logoutSuccessUrl("/");
.logout()是开启注销功能,.logoutSuccessUrl是设置注销之后跳转的页面
前端代码:
<a class="nav-link" th:href="@{/logout}">注销</a>
还可以设置注销时删除cookie和session等。
前面都是用的储存在内存中的用户名和密码来模拟的,这边学习一下真正从数据库中获取用户名密码。
首先新建一个UserDetailsServiceImpl实现UserDetailsService接口,重写其中的loadUserByUsername方法:
package com.jnshu.springboot_mybatis.config;
import com.jnshu.springboot_mybatis.pojo.Account;
import com.jnshu.springboot_mybatis.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
AccountService accountService;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountService.selectAccount(username);
if (account == null) {
return null;
} else {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_account"));
User user = new User(account.getUsername(), passwordEncoder.encode(account.getPassword()), authorities);
System.out.println("用户信息:" + user.getUsername() + " " + passwordEncoder.encode(account.getPassword()) + " " + user.getAuthorities());
return user;
}
}
}
接着配置SecurityConfig:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
/*auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("root").roles("account").password(new BCryptPasswordEncoder().encode("1234"));*/
}
接下来就可以用数据库中的用户进行登录了。
不过用之前的加密加盐工具加密过的密码就用不了了,springsecurity本身也有这个功能。
将之前的加密工具修改一下,实现PasswordEncoder接口,然后在验证的时候选择自定义的加密工具类即可。
package com.jnshu.springboot_mybatis.utils;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class Md5PasswordEncoder implements PasswordEncoder {
private final static String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
private String salt;
public void setSalt(String salt) {
this.salt = salt;
}
private static Md5PasswordEncoder instance = new Md5PasswordEncoder();
public Md5PasswordEncoder() {
}
//以单例模式构造
public static Md5PasswordEncoder getInstance() {
return instance;
}
private String mergePasswordAndSalt(CharSequence password) {
if (password == null) {
password = "";
}
if ((salt == null) || "".equals(salt)) {
return password.toString();
} else {
return password + "{" + salt + "}";
}
}
private String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte value : b) {
resultSb.append(byteToHexString(value));
}
return resultSb.toString();
}
private String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return HEX_DIGITS[d1] + HEX_DIGITS[d2];
}
/**
* MD5加密
*
* @param rawPassword 原始密码
* @return 加密后的md5密文
*/
@Override
public String encode(CharSequence rawPassword) {
String result = null;
try {
String algorithm = "MD5";
MessageDigest md = MessageDigest.getInstance(algorithm);
result = byteArrayToHexString(md.digest(mergePasswordAndSalt(rawPassword).getBytes(StandardCharsets.UTF_8)));
} catch (Exception ignored) {
}
return result;
}
/**
* 密码比较
*
* @param rawPassword 原始密码
* @param encodedPassword 加密后的密码
* @return boolean
*/
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(encode(rawPassword));
}
}
SecurityConfig配置类:
加密方式改为自定义md5加密。
评论