Spring Security

Spring Boot + Security实现简单验证登录操作

2018-09-09  本文已影响238人  double_Ji

利用spring security 实现简单的登陆验证,并且在登陆失败或者成功后进行对前端返回的处理。

GitHub地址

1.准备(数据库配置等)

本例子使用的Mysql + Hibernate

image

2.引入maven依赖

本例子需要的依赖有

基本的mysql,jpa,还有spring security的oauth2,jwt

image

3.新建表User,UserRole

创建entity:User和UserRole,在本例子中实际上只有User一个表就够了,毕竟只是验证用户名和密码嘛,但是我习惯每次创建User就手痒价格Role的表。

2个表多对多的关系也在代码中有用Hibernate写了,感兴趣的可以在Git上看一下。


/**

* Store User information.

*/

@Entity

@Table(name ="sys_user")

public class User {

private StringuserName;

    private StringuserDescription;

    private Stringpassword;

    private Listroles;

    @Id

    @Column(name ="user_name")

public StringgetUserName() {

return userName;

    }

public void setUserName(String userName) {

this.userName = userName;

    }

@Column(name ="user_desc")

public StringgetUserDescription() {

return userDescription;

    }

public void setUserDescription(String userDescription) {

this.userDescription = userDescription;

    }

@Column(name ="password")

public StringgetPassword() {

return password;

    }

public void setPassword(String password) {

this.password = password;

    }

@ManyToMany

    @JoinTable(name ="sys_user_role",

            joinColumns =@JoinColumn(name ="user_name", referencedColumnName ="user_name", updatable =false, insertable =false),

            inverseJoinColumns =@JoinColumn(name ="role_code", referencedColumnName ="role_code", updatable =false, insertable =false))

public ListgetRoles() {

return roles;

    }

public void setRoles(List roles) {

this.roles = roles;

    }

}

4.User Repository

此处只需要添加两个方法,findByUserName在UserDetialService load user的信息时候用,一个是测试用。


@Repository

public interface UserRepositoryextends JpaRepository {

UserfindByUserName(String userName);

    @Query(value ="select r.roleCode from User u inner join u.roles as r where u.userName = :userName")

ListqueryUserOwnedRoleCodes(@Param(value ="userName") String userName);

}

5.新建DatabaseUserDetailsService

新建DatabaseUserDetailsService继承UserDetailsService,并重写loadUserByUsername方法,在用户登陆时,spring会调用这个方法去获得user的信息(密码等),以对比页面传过来的用户名和密码是否正确。


@Override

public UserDetailsloadUserByUsername(String userName)throws UsernameNotFoundException {

User user =userRepository.findByUserName(userName);

    if (user ==null) {

//throw exception inform front end not this user

        throw new UsernameNotFoundException("user + " + userName +"not found.");

    }

List roleCodeList =userRepository.queryUserOwnedRoleCodes(userName);

    List authorities =

roleCodeList.stream().map(e ->new SimpleGrantedAuthority(e)).collect(Collectors.toList());

    UserDetails userDetails =new org.springframework.security.core.userdetails.User(

user.getUserName(),user.getPassword(),authorities);

    return userDetails;

}

6.新建WebSecuerityConfig

建立一个WebSecuerityConfig类继承WebSecurityConfigurerAdapter,并重写两个configure方法,

配置各种访问权限限制以及添加处理类

(1)不需要限制的用permitAll()放行即可。

(2).successHandler() 和 .failureHandler() 是配置登录失败或成功时的处理,后面有写这两个类的实现。

(3).authenticationEntryPoint()是没有登录就请求资源时的处理。


@Override

public void configure(HttpSecurity http)throws Exception {

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)

.and().csrf().disable()

.authorizeRequests()

.antMatchers("/v2/api-docs/**").permitAll()

.anyRequest().authenticated()

.and().formLogin().loginProcessingUrl("/api/login")

.successHandler(successHandler)

.failureHandler(failHandler)

.and().exceptionHandling().authenticationEntryPoint(entryPoint);

}

@Override

protected void configure(AuthenticationManagerBuilder auth)throws Exception {

auth.userDetailsService(userDetailsService);

}

7.登陆失败或成功的处理。

未登录就请求资源时,spring会交给AuthenticationEntryPoint处理。

登陆成功之后,spring会跳到AuthenticationFailHandler。

登陆失败之后,spring会跳到AuthenticationSuccessHandler。

所以我们要继承这两个方法,把想要返回给页面的信息在这两个类中写一下。


@Service("authenticationEntryPointImpl")

public class AuthenticationEntryPointImplimplements AuthenticationEntryPoint {

@Override

    public void commence(HttpServletRequest httpServletRequest,

                        HttpServletResponse httpServletResponse, AuthenticationException e)throws IOException {

httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());

    }

}


@Service("authenticationSuccessHandler")

public class AuthenticationSuccessHandlerextends SavedRequestAwareAuthenticationSuccessHandler {

@Override

    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response

, Authentication authentication)throws IOException {

logger.info("User: " + request.getParameter("username") +" Login successfully.");

        this.returnJson(response);

    }

private void returnJson(HttpServletResponse response)throws IOException {

response.setStatus(HttpServletResponse.SC_OK);

        response.setCharacterEncoding("UTF-8");

        response.setContentType("application/json");

        response.getWriter().println("{\"exceptionId\":\"null\",\"messageCode\":\"200\"," +

"\"message\": \"Login successfully.\",\"serverTime\": " + System.currentTimeMillis() +"}");

    }

}


@Service("authenticationFailHandler")

public class AuthenticationFailHandlerextends SimpleUrlAuthenticationFailureHandler {

@Override

    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)throws IOException, ServletException {

this.returnJson(response,exception);

    }

private void returnJson(HttpServletResponse response,

                            AuthenticationException exception)throws IOException {

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        response.setCharacterEncoding("UTF-8");

        response.setContentType("application/json");

        response.getWriter().println("{\"exceptionId\":\"null\",\"messageCode\":\"401\"," +

"\"message\": \""+ exception.getMessage() +"\",\"serverTime\": " + System.currentTimeMillis() +"}");

    }

}

8.Postman 测试

这是我数据库中存在的数据

image

没有登录直接发送普通时:

image

密码或用户名输入错误时,

image

用户名密码都正确时:

image
上一篇下一篇

猜你喜欢

热点阅读