Spring Security 为基于J2EE企业应用软件提供了全面安全服务,本文主要使用Springboot+Mybatis+Mybatis Plus+thymeleaf。
User实体类,封装角色
package com.strtz3.blog.model.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@TableName("tb_user")
@Data
public class User implements UserDetails {
@TableId(type = IdType.INPUT)
private Integer id;
private String username;
private String password;
/**
* 账号是否锁定
*/
private Boolean locked;
/**
* 账号是否能够使用
*/
private Boolean enabled;
/**
* 角色、多对多
*/
@TableField(exist = false)
private List<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 将roles进行整理
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
// 角色认证的要求,角色名必须是ROLE开始的(如果数据库中查出来的数据就是ROLE开始,该字符串可以省略)
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return authorities;
}
/**
* 账号是否未过期
*
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 账号是否未锁定
*
* @return
*/
@Override
public boolean isAccountNonLocked() {
return !locked;
}
/**
* 凭证(密码)是否过期
*
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 账号是否能够使用
*
* @return
*/
@Override
public boolean isEnabled() {
return true;
}
}
从数据库查询用户和角色,多对多的映射关系,使用了中间表
package com.strtz3.blog.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.strtz3.blog.model.pojo.Tag;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TagMapper extends BaseMapper<Tag> {
/**
* 根据article查询标签
* @param aid
* @return
*/
List<Tag> findTagsByAid(Integer aid);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.strtz3.blog.mapper.RoleMapper">
<select id="findByUid" resultType="com.strtz3.blog.model.pojo.Role">
select *
from tb_role
where id in (select role_id from tb_user_role where user_id = #{uid})
</select>
</mapper>
判断用户是否存在、返回登录成功的用户信息
package com.strtz3.blog.service.Impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.strtz3.blog.mapper.RoleMapper;
import com.strtz3.blog.mapper.UserMapper;
import com.strtz3.blog.model.pojo.User;
import com.strtz3.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
/**
* 根据用户名返回用户信息
*
* @param username 用户名
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询用户是否存在
User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
//查询存在的用户的角色
user.setRoles(roleMapper.findByUid(user.getId()));
return user;
}
}
将Spring Security加入到容器,交给springboot自动配置
package com.strtz3.blog.config;
import com.strtz3.blog.component.filter.VerifyCodeFilter;
import com.strtz3.blog.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private VerifyCodeFilter verifyCodeFilter;
@Autowired
UserService userService;
/**
* 权限控制
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//开启授权请求
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN");
http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class) //图片验证
.formLogin() //无权限,跳转登录页面
.loginPage("/loginPage")//进入登录页面的路径
.usernameParameter("username") //自定义接收前端的参数
.passwordParameter("password")
.and().rememberMe() //记住密码,cookie,默认保存两周
.rememberMeParameter("remember")//自定义接收前端的参数
.and().logout() //注销
.logoutSuccessUrl("/admin") //注销成功后跳转的url
.and().csrf().disable(); //注销失败可能存在的原因:关闭crtf防攻击功能
//同域名的iframe允许
http.headers().frameOptions().sameOrigin();
}
/**
* 授权认证
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
// auth.inMemoryAuthentication().passwordEncoder(passwordEncoder)
// .withUser("admin").password(passwordEncoder.encode("admin")).roles("ADMIN");
}
/**
* 加密
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 图片码过滤器
*/
@Bean
public VerifyCodeFilter verifyCodeFilter() {
return new VerifyCodeFilter();
}
}
前端显示登录的提示信息
<div th:if="${param.error}" th:text="${session?.SPRING_SECURITY_LAST_EXCEPTION?.message}">sadsda</div>