SpringSecurity实现用户认证授权系统

本文同步发布在是与非博客(www.zhuoerhuobi.cn)

随着是与非博客基础功能的完善,给我的网站加上用户认证授权系统这件事终于是提上日程了。

用户系统我们可以拆解为登录认证和授权访问这两个功能。我们先登陆账号,用户的状态就存在在网站了,然后网站再根据该用户的角色权限授权该用户访问某些页面和接口。

如果我们自己动手实现用户系统,可以料想到大致流程为:
读取用户输入的账户密码 --> 加密后和数据库中的用户表进行比对 --> 若比对成功,则读取数据库中用户的信息,登陆成功 --> 在我们已有的接口或页面上添加判断条件或拦截器,根据用户信息中的角色或者权限等字段判断是否让用户通行。

这么做的缺点也很明显,工作量大,并且认证系统和我们的业务代码高度耦合,不利于后期维护。

在这种情况下,用户系统相关框架应运而生,当下最流行的shrio和springsecurity都能很好的完成我们上面的需求,并且它们遵循了aop原则,并不需要更改我们的业务代码就可以加入用户系统功能,相当方便。

要引入springsecurity功能,我们首先要在pom文件中添加依赖:

<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-securityartifactId>
dependency>

这样,项目就引入了security模块。security默认拦截所有请求,而默认登录用户名为user,默认密码在服务启动时会打印在终端下。
SpringSecurity实现用户认证授权系统_第1张图片
security相关配置继承自WebSecurityConfigurerAdapter类,所以我们定义自己的MySecurityConfig类继承WebSecurityConfigurerAdapter,并重写其中几个方法。


@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetailService myUserDetailService;

    @Override
    public void configure(WebSecurity web) throws Exception {
		//不拦截静态资源
        web.ignoring().antMatchers("/css/**","/js/**","/fonts/**","/lib/**","/img/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();/*关闭防御csrf攻击功能*/
		//链式编程,可以连写若干个功能,为了方便理解,我们还是拆开来写。
        http.formLogin() /*开启表单登录*/
            .loginPage("/login")/*自定义我们自己的登陆页面*/
            .defaultSuccessUrl("/index?page=1").permitAll()/*自定义登录成功页面*/
            .and().authorizeRequests()
            .antMatchers("/login","/resources/**").permitAll()/*选择哪些页面不需要权限*/
            .antMatchers("/admin/**").hasRole("ADMIN");/*选择哪些页面必须要相应角色*/
			
        http.logout().logoutSuccessUrl("/");/*开启注销功能*/
        
        http.rememberMe().rememberMeParameter("rememberMe");/*开启记住我功能,这里的参数要和前端相应的参数name相同*/
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//认证规则里的用户从我们自定义的MyUserDetailService里读取,并用BCryptPasswordEncoder加密
        auth.userDetailsService(myUserDetailService).passwordEncoder(new BCryptPasswordEncoder());
    }

}

其中我们自定义的MyUserDetailService从数据库中读取用户信息:


@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    MyUserMapper myUserMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        MyUser user = myUserMapper.getUserByName(username);
        if (user != null) {
            return new User(user.getName(),user.getPassword(),AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole()));
        }
        else {
            throw new UsernameNotFoundException("用户\""+username+"\"不存在!");
        }
    }
}

为了给用户赋予角色,我们还要在用户表添加role字段,注意role要有ROLE_ 的前缀。

SpringSecurity实现用户认证授权系统_第2张图片

接下来我们来完成前端部分,其中用户名输入框的name属性设置为username,密码输入框设置为password

<form class="form-horizontal" action="/login" method="post">
	<span class="heading">用户登录span>
	<div class="form-group">
		<input type="text" name="username" class="form-control" id="inputEmail3" placeholder="用户名或电子邮件">
		<i class="fa fa-user">i>
	div>
	<div class="form-group help">
		<input type="password" name="password" class="form-control" id="inputPassword3" placeholder="密 码">
		<i class="fa fa-lock">i>
		<a href="#" class="fa fa-question-circle">a>
	div>
	<div class="form-group">
		<div class="main-checkbox">
			<input type="checkbox" id="checkbox1" name="rememberMe"/>
			<label for="checkbox1">label>
		div>
		<span class="text">Remember mespan>
		<button type="submit" class="btn btn-default">登录button>
	div>
form>

由于前端我们使用的是thymeleaf,而thymeleaf和security是有合作的包,所以我们再导入一个依赖方便我们操作前端:

<dependency>
	<groupId>org.thymeleaf.extrasgroupId>
	<artifactId>thymeleaf-extras-springsecurity5artifactId>
	<version>3.0.4.RELEASEversion>
dependency>

引入后我们就可以以sec:前缀来书写动态的html标签,类似于th:

<div class="pull-right login-nav">
	<ul>
		<li class="dropdown" sec:authorize="isAuthenticated()"> <a sec:authentication="name" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="color: white"><span class="caret">span>a>
			<ul class="dropdown-menu dropdown-menu-left">
				<li sec:authorize="hasRole('ADMIN')"><a title="进入后台管理系统" href="/admin/article">进入后台a>li>
				<li><a title="查看或修改个人信息" data-toggle="modal" data-target="#seeUserInfo">个人信息a>li>
				<li><a title="查看您的登录记录" data-toggle="modal" data-target="#seeUserLoginlog">登录记录a>li>
			ul>
		li>
		<li sec:authorize="isAuthenticated()"><a href="/logout" onClick="if(!confirm('是否确认退出?'))return false;"><button class="btn-login">退出登录button>a>li>
		<li sec:authorize="!isAuthenticated()"><a href="/login"><button class="btn-login" href="/login">请登录button>a>li>
	ul>
div>

这样,我们就实现了简单的登录认证功能,并对后台的接口和页面加以限制,只有管理员用户可以访问。具体效果可以在是与非博客进行体验。


这篇文章只是简单记录了我的springsecurity使用过程,其中还有很多坑和源码相关知识。如果看了这篇博文后你还想深入了解security的原理,请上网百度,或者我自己研究明白了或许会再出一篇文章专门讲解(不大可能)。

你可能感兴趣的:(web开发)