今天翻看了一下spring security,简单写了个数据库认证的demo,代码如下:
1.在pom.xml文件中引入如下坐标
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
2.application.properties中简单配置一下数据源信息;
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=mysql
#mybatis.mapperLocations=classpath:mapper/*.xml
3.先梳理后端,分别创建User和Role类,代码如下;
public class User implements UserDetails , Serializable {
private String id;
private String username;
private String password;
private List<Role> list;
public List<Role> getList() {
return list;
}
public void setList(List<Role> list) {
this.list = list;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return list;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isEnabled() {
return true;
}
}
public class Role implements GrantedAuthority, Serializable {
private String id;
private String roleName;
private String roleDesc;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
@JsonIgnore
@Override
public String getAuthority() {
return roleName;
}
}
4.创建mapper接口
UserMapper接口代码如下:
@Mapper
public interface UserMapper {
@Select("select id,username,password from user where username = #{username} and enable = 1")
@Results({
@Result(id = true,property = "id",column = "id"),
@Result(property = "list",column = "id",javaType = List.class,
many = @Many(select = "com.security.demo.mapper.RoleMapper.getRolesByUserId")
)
})
User getUser(@Param("username") String username);
}
RoleMapper接口如下:
@Mapper
public interface RoleMapper {
@Select("select role_name as roleName,role_desc as roleDesc from role,role_to_user where role.id = role_to_user.role_id and user_id = #{userId}")
List<Role> getRolesByUserId(String userId);
}
5.创建UserService接口
public interface UserService extends UserDetailsService {
}
实现类如下:
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.getUser(username);
if(user == null){
throw new UsernameNotFoundException("非法用户!!!");
}
return user;
}
}
6.WebSecurityConfig代码如下:
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) //启用基于注解的安全性
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userServiceImpl;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
// .inMemoryAuthentication()
// .withUser("xiaochen")
// .password("{noop}111")
// .roles("USER");
.userDetailsService(userServiceImpl).passwordEncoder(bCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 前后端分离就不需要添加这个
.antMatchers( "/css/**")
.permitAll()
// .regexMatchers("")
// .permitAll()
.anyRequest()
.authenticated()
// 前后端分离就不需要添加这个
.and()
.formLogin()
//设置登录用户名参数
.usernameParameter("username")
//设置登录密码参数
.passwordParameter("password")
//设置登录页
.loginPage("/login.html")
//设置登录访问的url
.loginProcessingUrl("/login")
// .successHandler(new AuthenticationSuccessHandler() {
// @Override
// public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
// httpServletResponse.setContentType("application/json;charset=UTF-8");
// PrintWriter writer = httpServletResponse.getWriter();
// writer.write("登录成功!!!");
// }
// })
// .successForwardUrl("/getUser")
// .failureHandler(new AuthenticationFailureHandler() {
// @Override
// public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
// httpServletResponse.setContentType("application/json;charset=UTF-8");
// PrintWriter writer = httpServletResponse.getWriter();
// writer.write("登录失败!!!");
// }
// })
.permitAll()
.and()
.logout()
.logoutUrl("/")
.logoutUrl("/loginOut")
.logoutSuccessUrl("/login.html")
// .logoutSuccessHandler(new LogoutSuccessHandler() {
// @Override
// public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
//
// }
// })
//session失效
.invalidateHttpSession(true)
//删除token
// .deleteCookies()
// .addLogoutHandler(new LogoutHandler() {
// @Override
// public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
//
// }
// })
.permitAll()
.and()
//实现跨域
// .cors()
// .and()
.csrf()
.disable();
}
7.简单写一接口
@RestController
public class UserController {
// @Secured("ROLE_ADMIN")
@RequestMapping("/getUser")
public String getUser(){
return "security demo";
}
}
8.创建启动类
@SpringBootApplication
public class ApplicationStart {
public static void main(String[] args) {
SpringApplication.run(ApplicationStart.class,args);
}
}
9.后端说完,说说前端,登录界面如下:(这里我只是用spring security默认登录也简单改了改,因而两个css文件就不在这里展示了)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Please sign in</title>
<link href="css/bootstrap.min.css" rel="stylesheet" >
<link href="css/signin.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">请 登 录</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="用户名" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="密码" required>
</p>
<input name="_csrf" type="hidden" value="ce8008cc-5914-4efd-92c9-ddb19566e3f3" />
<button class="btn btn-lg btn-primary btn-block" type="submit">登 录</button>
</form>
</div>
</body>
</html>
index.html 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Please sign in</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
</head>
<body>
<div class="container">
首页
<a href="/loginOut">注销</a>
</div>
</body></html>
数据库表这里就不分享了,这里只是涉及用户、角色及关联表。