SpringBoot整合SpringSecurity+Mybatis实现自定义登录

文章目录

  • 配置文件配置
    • Maven配置
    • Mysql相关的配置
  • 数据接口的实现
    • 数据表
    • 数据表对应的实体类
    • 数据访问类
    • 服务类
    • 控制类
  • SpringSecurity认证处理类
    • 认证成功处理类
    • 用户认证接口类
    • Security配置类
  • 前端实现
    • 登录页实现

配置文件配置

本文实现的是一个简单的自定义登录页,所以只需要配置Mysql即可

Maven配置

因为需要使用到Mysql和MyBatis所以需要添加相关的依赖

 <dependencies>
 	   
 	   <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.2version>
        dependency>
		
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>
 dependencies>

Mysql相关的配置

在application.properties中配置Mysql()

// An highlighted block
spring.datasource.url=jdbc:mysql://localhost:3306/blogrepository?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

通过上面的配置即可配置好Mysql,需要注意的时,新版本的Mysql在连接时需要指定UTC时区,通过serverTimeZone=GMT来指定。否则会出现下面的异常报错:
Java.sql.SQLException: The server time zone value ‘…???’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

数据接口的实现

数据表

id username passwd
1 root root

数据表对应的实体类

@Component
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private int id;
    private String username;
    private String passwd;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}

数据访问类

通过Mybatis的注解来实现数据库的访问

@Mapper
@Repository
public interface UserMapper {
    @Select("select id,username,passwd from user")
    List<User> select();
}

服务类

@Service
@Transactional
public class AuthencationService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    //实现该接口来查询对应的用户
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("前台用户名:"+username);
        List<User> userList= userMapper.select();
        User user = null;
        for (User userone : userList){
            System.out.println("数据库用户:" + userone.getUsername());
            if (userone.getUsername().equals(username)){
                user = userone;
                break;
            }
        }

        if (user == null){
            System.out.println("不存在该用户");
            throw new UsernameNotFoundException("用户不存在");
        }

        //添加用户权限。此处应该实现一个与User关联的Role表,以指定用户权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        //Sercurity的config的hasAnyRole方法会给权限添加ROLE_的前缀,所以必须要加上该前缀
        authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        return new org.springframework.security.core.userdetails.User(user.getUsername()
                ,user.getPasswd(),authorities);
    }
}

需要注意的是,在给用户添加权限时,需要加上ROLE_前缀,因为SpringSecurity会自动给设置的权限加上ROLE_前缀。此类为了简略所以直接添加了用户权限,实际应该实现一个与用户关联的权限表,从权限表中添加相关的权限。类中的控制台输出语句可以去掉。

控制类

@Controller
public class LoginController {
    @GetMapping("/authentication/login")
    public String authenticationLogin() throws IOException{
        return "login";
    }

    @GetMapping("/admin/index")
    public String indexPage(){
        return "index";
    }
}

SpringSecurity认证处理类

认证成功处理类

@Component
public class AuthenticationSucessHandler extends SimpleUrlAuthenticationSuccessHandler {

    //Spring Security 通过RedirectStrategy对象来负责所有重定向事务
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    //重写handle方法,来指定重定向的url
    @Override
    protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String targetUrl = determineTargetUrl(authentication);

        redirectStrategy.sendRedirect(request,response,targetUrl);
    }

    private String determineTargetUrl(Authentication authentication){
        String url="";

        //获取当前登录用户的角色权限合集
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

        //保存角色信息
        List<String> roles = new ArrayList<>();

        for (GrantedAuthority authority : authorities){
            System.out.println("拥有的权限为:" + authority.getAuthority());
            roles.add(authority.getAuthority());
        }

        //根据权限选择不同的Url,暂不做处理
        url = "/admin/index";

        return url;
    }

    //判断角色是否为ROLE_ADMIN
    private boolean isAdmin(List<String> roles){
        for (String str : roles){
            if (str.equals("ROLE_ADMIN")){
                return true;
            }
        }

        return false;
    }
}

用户认证接口类

@Component
public class CustmProvider implements AuthenticationProvider {
    @Autowired
    AuthencationService service;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //获取前端返回的用户名和密码
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken)
                authentication;
        String username = token.getName();//前台用户名
        String passwd = token.getCredentials().toString();//前台的密码
        System.out.println("前台密码:"+passwd);
        User user = (User) service.loadUserByUsername(username);
        if (user == null){
            throw new UsernameNotFoundException("Could not find the user!");
        }
        if (!user.getPassword().equals(passwd)){
            throw new BadCredentialsException("Password wrong!");
        }
        System.out.println("验证通过");
        return new UsernamePasswordAuthenticationToken(user,user.getPassword(),user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

Security配置类

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private CustmProvider custmProvider;

    @Autowired
    private AuthenticationSucessHandler authenticationSucessHandler;



    //设置密码的加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }




    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/authentication/*","/login")
                .permitAll()
                .antMatchers("/user/**").hasAnyRole("USER","ADMIN")
                .antMatchers("/admin/**").hasAnyRole("ADMIN")
                .antMatchers("**.html").hasAnyRole("NONE")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/authentication/login")//设置登录的路径(和Controller中的Mapping路径一致)
                .successHandler(authenticationSucessHandler)
                .loginProcessingUrl("/authentication/form")//处理前端数据的路径
                .usernameParameter("username")
                .passwordParameter("password");
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(custmProvider);
    }
}

前端实现

登录页实现



<head>
    <meta charset="UTF-8">
    <title>Logintitle>
head>
<body>
    <form name="loginForm" th:action="@{/authentication/form}" th:method="post">
        <table>
            <tr>
                <td>UserName:td>
                <td><input th:type="text" name="username" id="username" placeholder="UserName">td>
            tr>
            <tr>
                <td>Password:td>
                <td><input th:type="password" name="password" id="password" placeholder="Password">td>
            tr>
            <tr>
                <td><input th:type="submit" value="Login">td>
                <td><input th:type="reset" value="Reset">td>
            tr>
        table>
    form>
body>
html>

这里需要注意的地方是表格的action属性需要与security配置类的.loginProcessingUrl()方法设置的属性一致才并且提交的方式须为POST,这样才能正确的处理登录的数据,CusmProvider会无法获取到前端的数据。

你可能感兴趣的:(Spring,Boot)