一、创建项目
参考:浅试Security
二、实现用户鉴权
何为鉴权?说白了其实就是用户认证,用户输入用户名和密码,只有认证通过了才能使用我的系统。
在实际的项目开发中,账号和密码都是从数据库中查询出来的。所以,我们可以通过自定义逻辑来控制认证。在Security中,如果需要自定义用户认证逻辑(鉴权),只需要实现UserDetailsService接口即可。
2.1、鉴权服务类SecurityService
package demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
/**
* 自定义鉴权服务类
*/
@Service
public class SecurityService implements UserDetailsService {
@Autowired
@Lazy
private PasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据username,去数据库查该用户的信息
System.out.println("************");
System.out.println(username);
if("tom".equals(username)){
return new User("tom", encoder.encode("123"), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
} else {
throw new UsernameNotFoundException("用户名或密码错误");
}
}
}
Tip:实际开发中,我们一般会通过数据库来认证用户信息,大概实现思路是在自定义UserDetailsService类中的loadUserByUsername方法中根据用户名去数据库中查询用户信息,如果满足要求,则用户通过认证,如果不满足要求,则抛出一个UsernameNotFoundException异常,该异常时SpringSecurity内部定义的用于抛出用户不存在的异常。
2.2、Security配置类SecurityConfig
package demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Spring Security配置类
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SecurityService securityService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(securityService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置没有权限访问时跳转的自定义页面
http.formLogin() //表单登陆
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/test/index").permitAll(); //登录成功之后跳转路径
http.authorizeHttpRequests() //认证配置
.anyRequest() //任何请求
.authenticated(); //所有请求都拦截
http.csrf().disable(); //关闭跨站脚本攻击
}
/**
* 将PasswordEncoder注入到ioc容器
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
2.3、自定义登陆页面
如果需要自定义登陆页面,则需要在Security的配置类SecurityConfig中进行配置,如图:
- loginPage:设置登陆页面,当前案例登陆页面的位置是/resources/static/login.html
- loginProcessingUrl:设置登陆访问的路径
- defaultSuccessUrl:设置从login.html登陆成功之后跳转的路径,如果是从其他url访问,并且通过了认证,是不走这个 defaultSuccessUrl配置的路径的,直接跳转到当前访问的url
/resources/static/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
<!-- 这里务必注意,用户名和密码对应的name属性值必须是username和password-->
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
/test/index
@RequestMapping("/test/index")
public String index(){
return "欢迎使用xxx管理系统";
}
2.4、测试
2.4.1、直接访问Controller
访问用于测试的Controller,会进行鉴权
@RequestMapping("/hello")
public String hello(){
return "Hello Spring security";
}
浏览器输入http://localhost:8080/hello访问Controller,会直接跳转到自定义的登陆页面
输入正确的用户名(tom)和密码(123),通过认证之后则会将请求转发给刚刚浏览器输入的URL
如果用户名或者密码输入错误,则不会通过鉴权,重新跳转回自定义的登陆页面
2.4.2、测试自定义的登陆页面
如果直接访问自定义的登陆页面/resources/static/login.html,如果登陆成功则会将请求转发给预设的URL,当前案例预设的URL是一个Controller(/test/index)
三、源代码
Security鉴权.zip