SpringSecurity的学习

发布时间 2023-11-02 21:16:42作者: 陈强强强强强

前置知识

1.RBAC关系模型  

 这个图片很清晰了,一个用户可以对应多个角色一个角色可以对应多个权限,这样子我们就可以引出我们所设计的数据库

用户,角色,权限共三张表,再通过两张表将他们连起来,这样子就可以进行权限控制,知道用户就可以得知该用户可以访问哪些模块,不能访问哪些模块。

SpringSecurity

这个就开始正题了

1.首先链接数据库等等的就省略了。

2.导入各种依赖。

    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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>

<!-- mysql 的驱动和mybatisplus依赖-->

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>

<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<!--jwt依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>

<!-- security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

3.创建各种实体类和mapper

4.开始编写过滤器,将登录请求允许

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}


@Resource
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/user/login").anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();


}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

5.编写UserDetails

这个接口的实现仅仅存储用户的信息,后续会将该接口提供的用户信息封装到认证的对象Authentication中去。所以我们这里是按照用户账号获得该用户的权限并封装给Authentication中。

    @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//判断用户表中是否有该用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserName,username);
User user = userMapper.selectOne(wrapper);
if(Objects.isNull(user)){
throw new RuntimeException("账号或密码错误");
}
// 获得该用户的所有权限
List<String> permissionKeyList = menuMapper.selectPermsByUserId(user.getId());

return new LoginUser(user,permissionKeyList);
}

6. 编写登录的service


@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;

@Override
public ResponseResult login(User user) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
Authentication authenticate = authenticationManager.authenticate(authenticationToken);

if(Objects.isNull(authenticate)){
throw new RuntimeException("账号密码错误");
}
//使用userid生成token
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userId = loginUser.getUser().getId().toString();
String jwt = JwtUtil.createJWT(userId);
//authenticate存入redis
redisCache.setCacheObject("login:"+userId,loginUser);
//把token响应给前端
HashMap<String,String> map = new HashMap<>();
map.put("token",jwt);
return new ResponseResult(200,"登陆成功",map);
}

 

今日碰到的问题

1.有关Authentication authenticate = authenticationManager.authenticate(authenticationToken);堆栈溢出的报错,

UserDetailsService不是自己写的是SpringSecurity自带的,直接继承就行,我那时候不知道还自己写了个UserDetailsService,然后一直报错堆栈溢出,找了半天的错。

2.The signing key’s algorithm ‘AES’ does not equal a valid HmacSHA* algorithm name and cannot be used

 修改为HmacSHA256,修改完后大概率报错长度不够,我们只需要将以下的明文密钥修改的长一点就可以了。