Spring Security简单的登陆验证授权

2021-06-17 13:02

阅读:402

(1)其中 getAuthorities 方法是获取用户角色信息的方法,用于授权。不同的角色可以拥有不同的权限。

(2)账户未过期、账户未锁定和密码未过期我们这里没有用到,直接返回 True,你也可以根据自己的应用场景写自己的业务逻辑。

(3)为了区分是否是同一个用户,重写 equals 和 hashCode 方法。

因为实现接口之后可以获得数据库中的真是存在的信息;

使用这个框架之间我们要引入它,首先要在web.xml文件中引入它

springSecurityFilterChainclass>org.springframework.web.filter.DelegatingFilterProxyclass>
springSecurityFilterChain/*

 

然后UsernamePasswordAuthenticationFilter这个过滤器会接受到此方法,在源码里面已经帮我们实现获得密码以及用户名的操作,并且规定post请求方法
具体代码如下:

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (this.postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    } else {
        String username = this.obtainUsername(request);
        String password = this.obtainPassword(request);
        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        this.setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

 


在现实生活中,开发中可以增加的逻辑很多,所以一般都会重写这个方法;我们要建一个自己的类去继承这个类:
public class AccountAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private String codeParameter = "code";

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String username = this.obtainUsername(request);
        String password = this.obtainPassword(request);
        String code = this.obtainCode(request);
        String caChecode = (String)request.getSession().getAttribute("VERCODE_KEY");
        boolean flag = CodeValidate.validateCode(code,caChecode);
        if(!flag){
            throw new UsernameNotFoundException("验证码错误");
        }
        if(username == null) {
            username = "";
        }
        if(password == null) {
            password = "";
        }
        username = username.trim();
        //通过构造方法实例化一个 UsernamePasswordAuthenticationToken 对象,此时调用的是 UsernamePasswordAuthenticationToken 的两个参数的构造函数
        //其中 super(null) 调用的是父类的构造方法,传入的是权限集合,因为目前还没有认证通过,所以不知道有什么权限信息,这里设置为 null,然后将用户名和密码分别赋值给
        // principal 和 credentials,同样因为此时还未进行身份认证,所以 setAuthenticated(false)。
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        //setDetails(request, authRequest) 是将当前的请求信息设置到 UsernamePasswordAuthenticationToken 中。
        this.setDetails(request, authRequest);
        //通过调用 getAuthenticationManager() 来获取 AuthenticationManager,通过调用它的 authenticate 方法来查找支持该
        // token(UsernamePasswordAuthenticationToken) 认证方式的 provider,然后调用该 provider 的 authenticate 方法进行认证)。
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainCode(HttpServletRequest request) {
        return request.getParameter(this.codeParameter);
    }
}

 

里面我们完成了一个验证码的验证工作,并且把仅为post请求给屏蔽,获取到用户名和用户密码后,我们把它放在了UsernamePasswordAuthenticationToken类里,进去之后看到了
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
}

 

代码中给予了注释,然后setDetails将其存入UsernamePasswordAuthenticationToken之中,然后我们通过getAuthenticationManager()
获取AuthenticationManager这个接口,在调用接口里的方法,我们继续查找会发现AuthenticationManager这个类实现了这个接口的方法,
在方法中它又调用了AuthenticationProvide这个接口,那AuthenticationProvide这个接口的实现类是AbstractUserDetailsAuthenticationProvider
并且实现了authenticate方法,在这个方法里面引用了两个重要的方法additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);
user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);
那这两个方法在子类
DaoAuthenticationProvider中实现,两个方法上面都有代码,但是我们再看一下其中重点的方法

protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    UserDetails loadedUser;
    try {
    //很关键
        loadedUser = this.getUserDetailsService().loadUserByUsername(username);
    } catch (UsernameNotFoundException var6) {
        if (authentication.getCredentials() != null) {
            String presentedPassword = authentication.getCredentials().toString();
            this.passwordEncoder.isPasswordValid(this.userNotFoundEncodedPassword, presentedPassword, (Object)null);
        }

        throw var6;
    } catch (Exception var7) {
        throw new InternalAuthenticationServiceException(var7.getMessage(), var7);
    }

    if (loadedUser == null) {
        throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
    } else {
        return loadedUser;
    }
}

 

那个注释的地方是要获得一个UserDetails,上面有说到UserDetailsService常见的实现类有JdbcDaoImpl,InMemoryUserDetailsManager,为了简化我们自己写一个实现类,
因为结合我们pojo对象实现了UserDetails的接口,所以我们创建如下类:
public class AccountDetailsService implements UserDetailsService{
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByEmail(username);
        if(user == null){
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        List roles = roleService.findByUid(user.getId());
        user.setRoles(roles);
        return user;
    }
}

 


实现了loadByUsername的方法。到此为止我们我们在逆向的回到了UsernamePasswordAuthenticationFilter上,且返回了一个Authentication对象。
我们在第一个关键词SecurityContextHolder中将其取出,做一些自己的业务逻辑。


工作到此还没有结束,我们还要去授权,对认证通过的人去授权,这里我们可以xml去配置这些信息:我们前面留了一个问题就是salt加密密码验证,我们前面还不知道salt
对象是什么,所以需要配置一下


 


其实salt可以自己代码去配置,通过这个xml去配置也行,最紧要的还是要和你原来数据库密码的加密方式有关系,我这里是用了pojo对象里的用户名作为salt对象,
所以我的密码加密方式就是username+password再用MD5加密了。那还有一个重要的工作就是授权配置

 

这些都是基础的一些授权操作,还有配置在我们的AccountAuthenticationFilter类中是不是通过了验证
class="***.***.**.**.AccountAuthenticationFilter">
    class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
            class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
            

 

其中defaultTargetUrl和defaultFailureUrl是通过和不通过的一些采取措施,通常是一些页面跳转。
其余的配置文件信息,我还没有琢磨透,以后有时间在发表一篇。


最后:用一张图大致的总结下它的具体流程(本图来自王林永老师的gitchat):

技术分享图片

 


上一篇:C# WCF初始

下一篇:Python07,字典


评论


亲,登录后才可以留言!