springboot之集成Security,实现认证授权,权限控制
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index() {
return "index";
}
@RequestMapping("/toLogin")
public String toLogin() {
return "views/login";
}
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id) {
return "views/level1/" + id;
}
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id) {
return "views/level2/" + id;
}
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id) {
return "views/level3/" + id;
}
}
然后就可以开始重点的部分了。
<!--thymeleaf整合包-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<!--boot-starter-security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
//认证
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()//任何人都可以访问
.antMatchers("/index").permitAll()
.antMatchers("/level1/**").hasRole("vip1")//需要vip?权限,下同
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
http.formLogin();//开启登录页面
}
}
认证步骤:
1. 继承 WebSecurityConfigurerAdapter 类
2. 重写 configure(HttpSecurity http) 方法,
3. 方法里面写你需要的配置
4. 开启注释 @EnableWebSecurity,托管给springboot。
一旦给页面写了权限认证,在新版的security框架中,进入需要权限的页面,会自动判断跳转一个登录页面,自带的。然后要求你登录。
//授权
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("fang").password(new BCryptPasswordEncoder().encode("123123")).roles("vip1", "vip2", "vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123123")).roles("vip1", "vip2")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123123")).roles("vip1");
}
授权步骤:
1. 重写 configure(AuthenticationManagerBuilder auth) 方法
2. 方法里面写你需要的配置
说明一下
方法中的auth.inMemoryAuthentication()
表示在内存中认证,.passwordEncoder(new BCryptPasswordEncoder())
是密码加密。roles()
授权
如果需要用数据库认证,看下面官网的例子
@Autowired
private DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
这样一来,用户的授权和认证都可以啦。运行测试一下。
或者用我们自己写的方法
@Autowired
private UserDetailsService userDetailsService;//自己写的
// 授权
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
import com.fang.blogsystem.mapper.UserMapper;
import com.fang.blogsystem.pojo.DO.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Bernie_xin
* @create 2020/12/4 16:16
**/
@Service("userDetailsService")//注意一定要加
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper loginUserMapper;
//在这里返回用户名和密码以及权限
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//根据用户名做查询
User user = loginUserMapper.findUser(s);
if (user == null){
throw new UsernameNotFoundException("用户名不存在");
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");//这里本来也应该是数据库连表查询的
return new org.springframework.security.core.userdetails.User(user.getUsername(),//这里返回的user一定要是springframework.security的,由于我上面自己的user重名了,只能这么写。建议自己的用户类不需要写user,用sys_user之类的
new BCryptPasswordEncoder().encode(user.getPassword()),
auth);
}
}
没问题则继续
我们上面用的是security自带的首页页面,但是我想用我自己的页面。怎么设置呢?
很简单,在 http.formLogin()
后面继续 .loginPage("/toLogin")
。toLogin是我们前面写的去登录页面的请求。
我们在登录之后,首页就不应该再有什么登录的按钮啦,应该是注销按钮。
<!--登录注销-->
<div class="right menu">
<!--未登录-->
<div sec:authorize="!isAuthenticated()">
<a th:href="@{/toLogin}">
登录
</a>
</div>
<!--注销-->
<div sec:authorize="isAuthenticated()">
<a th:href="@{/toLogin}">
注销
</a>
</div>
通过sec:authorize="!isAuthenticated()
判断是否登录。使用这个之前,需要导入命名空间。不导入也可以使用,但是会飘红报错。
导入方法:
页面顶部的html标签里面加上
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
然后要开启注销。一行代码搞定
http.logout().logoutSuccessUrl("/");//logoutSuccessUrl("退出成功后跳转的页面")
最后就是把那些没有访问权限的页面隐藏。
也不难。就是在链接外面写一个div,里面sec:authorize="hasRole('权限')"
,看下面的例子
<div sec:authorize="hasRole('vip1')">
<a th:href="@{/level1/1}">Level-1-1</a>
</div>
然后测试,发现没有vip1
,我都看不到Level-1-1
。完成!
security学习的简单记录。如果这个篇博客对你有帮助。麻烦点个赞!