标签:忽略 取出 lte OLE art author 要求 阅读 none
@
本教程是基于SpringMVC而创建的,不适用于WebFlux。(如果你不知道这两者,可以忽略这句提示)
所有的技术是为了解决实际问题而出现的,所以我们并不空谈,也不去讲那么多的概念。在这样一个系统中,有三个接口,需要授权给三种权限的人使用,如下表:
接口地址 | 需要的权限描述 | 可访问的权限组名称 |
---|---|---|
visitor/main | 不需要权限,也不用登录,谁都可以访问 | |
admin/main | 必须登录,只有管理员可以访问 | ADMIN |
user/main | 必须登录,管理员和用户权限都能访问 | USER和ADMIN |
在Controller中判断用户是否登录和用户的权限组判断是否可以访问
这是最不现实的解决方案,可是我刚进公司时的项目就是这样设计的,当时我还觉得很高大尚呢。
使用Web应用的三大组件中和过滤器(Filter)进行判断
这是正解,SpringSecurity也正是用的这个原理。如果你的项目足够简单,建议你直接使用这种方式就可以了,并不需要集成SpringSecurity。这部分的示例在代码中有演示,自己下载代码查看即可。
我们可以直接使用SpringSecurity框架来解决这个问题
? 网上的教程那么多,但是讲的都不清不楚。所以,请仔细阅读下段这些话,这要比后边的代码重要。
? SpringSecurity主要有两部分内容:
这里的登录是对于浏览器访问来说的,因为如果是前后端分离时,使用的是Token进行授权的,也可以理解为登录用户,这个后边会讲。这里只是为了知识的严谨性才提到了这点
<!-- 不用写版本,继承Springboot的版本-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
是支持使用xml进行配置的,但是在SpringBoot中更建议使用Java注解配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 配置用户权限组和接口路径的关系
* 和一些其他配置
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 对请求进行验证
.antMatchers("/visitor/**").permitAll()
.antMatchers("/admin/**").hasRole("ROLE_ADMIN") // 必须有ADMIN权限
.antMatchers("/user/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN") //有任意一种权限
.anyRequest() //任意请求(这里主要指方法)
.authenticated() //// 需要身份认证
.and() //表示一个配置的结束
.formLogin().permitAll() //开启SpringSecurity内置的表单登录,会提供一个/login接口
.and()
.logout().permitAll() //开启SpringSecurity内置的退出登录,会为我们提供一个/logout接口
.and()
.csrf().disable(); //关闭csrf跨站伪造请求
}
}
上边的配置主要内容有两个:
说明:
? 配置了上边的接口和用户权限角色的关系后,就是要配置我们的用户名和密码了。如果没有正确的用户名和密码,神仙也登录不上去。
? 关于这个,网上的教程有各种各样的配置,其实就一个接口,我们只需要实现这个接口中的方法就可以了。接口代码如下:
package org.springframework.security.core.userdetails;
public interface UserDetailsService {
/**
* 在登录的时候,就会调用这个方法,它的返回结果是一个UserDetails接口类
*/
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
? 来看一下这个接口,如果想扩展,可以自己写一个实现类,也可以使用SpringSecurity提供的实现
public interface UserDetails extends Serializable {
// 用户授权集合
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
? UserDetailsServicer接口的实现类
@Configuration
public class UserDetailsServiceImpl implements UserDetailsService {
/**
* 这个方法要返回一个UserDetails对象
* 其中包括用户名,密码,授权信息等
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/**
* 将我们的登录逻辑写在这里
* 我是直接在这里写的死代码,其实应该从数据库中根据用户名去查
*/
if (username == null) {
//返回null时,后边就会抛出异常,就会登录失败。但这个异常并不需要我们处理
return null;
}
if (username.equals("lyn4ever")) {
//这是构造用户权限组的代码
//但是这个权限上加了ROLE_前缀,而在之前的配置上却没有加。
//与其说这不好理解,倒不如说这是他设计上的一个小缺陷
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> list = new ArrayList<>();
list.add(authority);
//这个user是UserDetails的一个实现类
//用户密码实际是lyn4ever,前边加{noop}是不让SpringSecurity对密码进行加密,使用明文和输入的登录密码比较
//如果不写{noop},它就会将表表单密码进行加密,然后和这个对比
User user = new User("lyn4ever", "{noop}lyn4ever", list);
return user;
}
if (username.equals("admin")) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority authority1 = new SimpleGrantedAuthority("ROLE_ADMIN");
List<SimpleGrantedAuthority> list = new ArrayList<>();
list.add(authority);
list.add(authority1);
User user = new User("admiin", "{noop}admin", list);
return user;
}
//其他返回null
return null;
}
}
? 分别访问上边三个接口,可以看到访问结果和上边的流程是一样的。
标签:忽略 取出 lte OLE art author 要求 阅读 none
原文地址:https://www.cnblogs.com/youngdeng/p/12869018.html