SpringSecurity框架的认证和授权过程

一、认证过程

1、编写自定义的过滤器TokenLoginFilter,继承UsernamePasswordAuthenticationFilter,重写

attemptAuthentication、successfulAuthentication、unsuccessfulAuthentication方法,attemptAuthentication方法获取前端提交的用户名和密码,封装成Authentication对象。

successfulAuthentication方法认证成功时调用,unsuccessfulAuthentication认证失败时调用。

package com.atguigu.filter;

import com.atguigu.entity.SecurityUser;
import com.atguigu.entity.User;
import com.atguigu.security.TokenManager;
import com.atguigu.utils.utils.R;
import com.atguigu.utils.utils.ResponseUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;
    private AuthenticationManager authManager;

    public TokenLoginFilter(AuthenticationManager authManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
        this.authManager = authManager;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST"));
    }

    //获取表单提交的用户名和密码
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            return authManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    //认证成功调用的方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        SecurityUser user = (SecurityUser)authResult.getPrincipal();
        String token =tokenManager.createToken(user.getCurrentUserInfo().getUsername());
        redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(),user.getPermissionValueList());
        ResponseUtil.out(response, R.ok().data("token",token));
    }

    //认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, R.error());
    }


}

2、自定义UserDetailsServiceImpl类,实现UserDetailsService接口,重写loadUserByUsername

方法(从数据库中根据用户名查询用户密码、用户权限等),封装成User对象返回。

package com.atguigu.aclservice.service.impl;

import com.atguigu.aclservice.entity.User;
import com.atguigu.aclservice.service.PermissionService;
import com.atguigu.aclservice.service.UserService;
import com.atguigu.entity.SecurityUser;
import com.atguigu.security.DefaultPasswordEncoder;
import com.atguigu.utils.utils.MD5;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private DefaultPasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.selectByUsername(username);
        if (user==null){
            throw new UsernameNotFoundException("用户名不存在");
        }
        com.atguigu.entity.User curUser=new com.atguigu.entity.User();
        BeanUtils.copyProperties(user,curUser);
        List<String> permissionList=permissionService.selectPermissionValueByUserId(user.getId());
        SecurityUser securityUser=new SecurityUser();
        securityUser.setCurrentUserInfo(curUser);
        securityUser.setPermissionValueList(permissionList);
        return securityUser;
    }
}

3、查看源码中DaoAuthenticationProvider类,继承AbstractUserDetailsAuthenticationProvider,additionalAuthenticationChecks方法将前端用户提交的密码和数据库中查询的密码进行匹配,匹配相同即为认证成功。

 4、若认证成功,调用TokenLoginFilter中successfulAuthentication方法,若认证失败,调用TokenLoginFilter中unsuccessfulAuthentication方法,将结果返回给前端。

2、授权过程 

1、自定义TokenAuthFilter类,继承BasicAuthenticationFilter类,重写doFilterInternal方法,

根据token获取到用户信息,再从redis中查询用户权限,进行授权,放行。

package com.atguigu.filter;

import com.atguigu.security.TokenManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class TokenAuthFilter extends BasicAuthenticationFilter {
    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;

    public TokenAuthFilter(AuthenticationManager authenticationManager, TokenManager tokenManager,RedisTemplate redisTemplate) {
        super(authenticationManager);
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        UsernamePasswordAuthenticationToken authRequest=getAuthentication(request);
        if (authRequest!=null){
            SecurityContextHolder.getContext().setAuthentication(authRequest);
        }
        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request){
        String token=request.getHeader("token");
        if (token!=null){
            String username = tokenManager.getUserInfoFromToken(token);
            List<String> permissionList = (List<String>) redisTemplate.opsForValue().get(username);
            Collection<GrantedAuthority> authorities=new ArrayList<>();
            for (String permission:permissionList){
                SimpleGrantedAuthority auth= new SimpleGrantedAuthority(permission);
                authorities.add(auth);
            }
            return new UsernamePasswordAuthenticationToken(username,token,authorities);
        }
        return null;
    }

}

3、代码逻辑如下图所示

 

 
 
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security是一个开源的安全框架,提供了基于权限的访问控制、身份认证安全性事件发布等功能。在Spring Boot应用中使用Spring Security可以非常方便地实现用户身份认证授权Spring Security实现身份认证授权的步骤如下: 1.添加Spring Security依赖,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2.创建一个继承自WebSecurityConfigurerAdapter的配置类,并重写configure方法,配置用户认证授权信息。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("{noop}password").roles("USER") .and() .withUser("admin").password("{noop}password").roles("USER", "ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/**").hasAnyRole("USER", "ADMIN") .and().formLogin(); } } ``` 上述代码中,configureGlobal方法配置了两个用户,一个是user,一个是admin,密码都是password,其中admin用户具有ADMIN角色,user用户具有USER角色。configure方法配置了访问/admin/**路径的请求需要ADMIN角色,访问其他路径的请求需要USER或ADMIN角色,并启用了表单登录。 3.在应用程序的配置文件中配置用户名和密码。例如: ```properties spring.security.user.name=user spring.security.user.password=password ``` 以上就是Spring Security实现身份认证授权的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值