SpringBoot2整合Sercurity5.X

简介

本博客主要针对的是,SpringBoot2与Sercurity 5.x的整合,其中利用的技术如下

  1. 自定义认证类
  2. 链接数据库访问
  3. 用户的角色变更,但是角色权限不能变更
  4. 一些错误分析以及解决
  5. 基于注解实现的权限控制

整体思路如下

  1. 导入依赖的pom文件
  2. 确定资源访问的路径以及权限
  3. 配置Sercurity
  4. 实现自定义认证类
  5. 实现数据库访问

POM文件

<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

确定页面权限如下

在这里插入图片描述

  • 其中index页面和login页面不设置权限,所有用户均可访问
  • Welcome页面,只有登录过后的用户可以访问
  • admin页面,只有拥有“admin”权限的用户可以访问
  • ceshi页面,只有拥有“ceshi”权限的用户可以访问
  • 403页面,是因为权限不够,会报状态码403的错误,springboot默认,在error文件夹下创建状态码文件即可处理错误页面,无需多的配置
Controller文件
@Controller
public class UserController {

    @RequestMapping(value = { "", "/index" }, method = RequestMethod.GET)
    public String home() {
        
        return "index";
    }

    @RequestMapping(value = {  "/ceshi" }, method = RequestMethod.GET)
    public String ceshi() {
        
        return "ceshi";
    }

    @RequestMapping(value = "/welcome", method = RequestMethod.GET)
    public String userPage() {
        
        return "welcome";
    }

    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public String adminPage() {
        
        return "admin";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login() {
        
        return "login";
    }

}

配置sercurity配置文件

@Configuration
@EnableWebSecurity
public class MySercurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public MyUserDetailsService myUserDetailsService(){
        return new MyUserDetailsService();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
       return  new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/index")
                .permitAll()
                .antMatchers("/admin").access("hasRole('admin')")
                .antMatchers("/welcome").hasAnyRole("admin","user")
                .antMatchers("/ceshi").access("hasRole('ceshi')")
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/welcome")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }
}

  • 针对前面的两个bean下面会给出详细讲解,这段先不说

  • configure(AuthenticationManagerBuilder auth)重写的这个方法,就是我们的认证方法,也就是我们接下来需要自定义用户认证类的方法

  • configure(HttpSecurity http)这个就是权限拦截的方法,接下来对里面的配置进行讲解

  • http.authorizeRequests()这段代码是指,通过这个方法为所有的请求进行权限配置

  • antMatchers("/","/index") .permitAll()这一行代码是值针对某些路径直接放行,所有用户都可以访问,主要用于我们的首页、静态资源、登录注册等

  • antMatchers("/admin").access("hasRole('admin')")这一行代码一样的,就是针对某些路径,只允许具备这个角色访问,也就是对角色的权限进行分配了(ps:这里需要注意,SpringSercurity会自动帮我们拼接“ROLE_”,也就是我们实际上是“ROLE_admin”而不是“admin”)

  • hasAnyRole("admin","user")这行代码,就是指针对某些路径,可以多个角色一起访问,都具备访问资格

  • formLogin() .loginPage("/login") .defaultSuccessUrl("/welcome")这一行代码,也很好理解,就是开启我们的登录页面,如果我们不要loginPage("/login")这个的话,就是使用Sercurity默认的登录页面,同时我们需要注意,我们自定义的页面,用户名和密码只能是(username,password)否则,你需要在这里进行别名配置,后面defaultSuccessUrl("/welcome")就是登录成功默认跳转的界面,安然也有登录失败跳转的界面了

  • logout() .permitAll();这最后一句,就更容易理解了,也就是一个退出按钮而已,但是,我们需要注意,我们的页面提交按钮应该如下
    <form th:action="@{/logout}" method="post"> <input type="submit" value="登出"/> </form>

在这里插入图片描述

自定义认证类

public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        User user=userDao.getUser(s);
        if (user==null){
            throw new UsernameNotFoundException("not found");
        }else {
            List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
            for (String role:user.getRole()) {
                grantedAuths.add(new SimpleGrantedAuthority(role));
            }
            return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuths);
        }
    }


}

数据库访问(模拟实现,没真实链接)

@Repository
public class UserDaoImpl implements UserDao {


    private static Map<String, User> userMap=new HashMap<>();

    static{
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String str=passwordEncoder.encode("123456");
        System.out.println(str);
        User user=new User("zhangsan",str, Arrays.asList("ROLE_admin","ROLE_ceshi"));
        userMap.put(user.getUsername(),user);
        user=new User("lisi",str, Arrays.asList("ROLE_user"));
        userMap.put(user.getUsername(),user);
    }
    @Override
    public User getUser(String username) {
        return userMap.get(username);
    }
}

  • 从上面的两个方法,就可以看出,自定义认证类其实很简单,就是实现一个UserDetailsService接口,然后重写里面的方法就ok
  • User user=userDao.getUser(s);这里首先获取我们登陆的用户,然后进行判断,看是否为空
  • 如果为空,直接抛出异常
  • 不为空,我们就新建一个List,以及一个User
  • 其实,这个写法相对比较固定,List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();首先新建一个角色链表,获取当前用户所有的角色,然后再返回一个User对象也就好了

自定义认证类的配置

  1. 我们首先完成了自定义认证类的编写,同时绑定了数据库的链接,但是这是不够,我们还需要吧这个类注入到配置文件中

  2. 这就到了我们上一步涉及到了两个Bean了

    @Bean
    public MyUserDetailsService myUserDetailsService(){
    	return new MyUserDetailsService();
     }
    
    @Bean
    public PasswordEncoder passwordEncoder(){
       return  new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService()).passwordEncoder(passwordEncoder());
    }
    
  • 这里就是将我们自定义的认证类注入进入,让Sercurity的配置类可以读取到
  • 其中的PasswordEncoder,是密码加密的,因为是Sercurity 5.X中必须使用的,不然会出错,下面会截图说明

总结

通过以上的几个步骤,已经简单的完成了一个基于数据库的整合了,同时,你也可以自己写一个修改角色的方法,因为这里的角色都是数据库查出来的,所以可以灵活更改

下面我给出一些错误截图,以及解决方案

错误一:

在这里插入图片描述

这个错误,就是因为Sercurity 5.X中,必须注入PasswordEncoder,我们只需要将以下代码加入就可以
在这里插入图片描述

错误二:

在这里插入图片描述
这个错误,是因为我们在保存的时候,没有保存为BCryptPasswordEncoder的形式,解决方法如下
在这里插入图片描述

对于权限的配置,还有一种基于注解的方式

对于这种基于注解的方式,好像是Sercurity 4.X开始的,具体不清楚,具体配置如下

老配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意我这里红线框出来的部分

新配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

源代码地址

源代码链接

友情提示

${#httpServletRequest.remoteUser}]

这个方法的返回值,参考API文档给出的如下解释
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值