springboot第25集:实体类定义规则

PO:持久化对象,一个PO对象对应一张表里面的一条记录。全部对应

VO:View视图对象,用来在页面中展示数据的,页面需要哪些字段属性就添加哪些,查询出来之后赋值操作比PO对象要简单。所以提高性能。

DTO:数据传递对象,如果要查询的结果集有多张表,或者从多个表获得的数据就可以封装DTO对象,把这些表的数据全部封装到一起,形成一个对象。

POJO:中间形态,可以在PO,VO,DTO之间互相转换。

POJO在保存数据,PO

POJO在表示层,VO

POJO数据传递,DTO

package com.xxx.app.controller;

import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.xxx.common.core.domain.AjaxResult;
import com.xxx.common.core.domain.entity.SysMenu;
import com.xxx.common.core.domain.entity.SysUser;
import com.xxx.common.core.domain.model.LoginBody;
import com.xxx.common.utils.SecurityUtils;
import com.xxx.framework.web.service.SysLoginService;
import com.xxx.framework.web.service.SysPermissionService;
import com.xxx.system.service.ISysMenuService;

/**
 * 登录验证
 *
 */
@RestController
public class SysLoginController
{
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
//        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
//                loginBody.getUuid());
//        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        return ajax;
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }
}
//        AjaxResult ajax = AjaxResult.success();
//        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
//                loginBody.getUuid());
//        ajax.put(Constants.TOKEN, token);
//        return ajax;

一般流程是下面这样。

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie。

4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

private String createToken(Map<String, Object> claims) {
 String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512,secret).compact();
 return token;
}
20ec7f3824cbc8950ae2181817907455.png
image.png
10092e32ba2208b76bb79187feaaca7d.png
image.png
public String createToken(LoginUser loginUser)
{
 String token = IdUtils.fastUUID();
 loginUser.setToken(token);
 setUserAgent(loginUser);
 refreshToken(loginUser);
 Map<String, Object> claims = new HashMap<>();
 claims.put(Constants.LOGIN_USER_KEY, token);
 return createToken(claims);
}
tokenService.getLoginUser(request);
Claims claims = parseToken(token);
private Claims parseToken(String token)
{
    return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
}
private String getToken(HttpServletRequest request)
{
    String token = request.getHeader(header);
    if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
    {
        token = token.replace(Constants.TOKEN_PREFIX, "");
    }
    return token;
}
ed1e1a2e22c9fb39fc3ea65d4daafffe.png
image.png
const whiteList = [];
router.beforeEach((to, from, next) => {
 NProgress.start()
 if (getToken
})
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
</dependency>

添加一个配置类,配置拦截的路径

@Configuration
public class SecurityConfig extends WebSecurityConfigureAdapter {
 @Override
 protected void configure(HttpSecurity http) throws Exception {
  http.formLogin() // 表单登录
      .add()
      .authorizeRequests() // 认证配置
      .anyRequest() // 任何请求
      .authenticated(); // 需要身份验证
 }
}

编写一个简单的controller测试

@RequestMapping("hello")
@RestController
public class HelloController {
 @GetMapping("test")
 public String test() {
  return "spring security";
 }
}
e95ffa6878bf87b53b94c7789a188bb6.png
image.png

(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。

(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。

(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。

(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
}

Authentication authentication = SecurityContextHolder.getContext().getAuthentication()
/**
 * 获取Authentication
 */
public static Authentication getAuthentication()
{
    return SecurityContextHolder.getContext().getAuthentication();
}

Authentication: 存储了认证信息,代表当前登录用户

SeucirtyContext: 上下文对象,用来获取Authentication

SecurityContextHolder: 上下文管理对象,用来在程序任何地方获取SecurityContext

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
    return super.authenticationManagerBean();
}
@RestController
@RequestMapping("/API")
public class LoginController {
    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping("/login")
    public String login(@RequestBody LoginParam param) {
        // 生成一个包含账号密码的认证信息
        Authentication token = new UsernamePasswordAuthenticationToken(param.getUsername(), param.getPassword());
        // AuthenticationManager校验这个认证信息,返回一个已认证的Authentication
        Authentication authentication = authenticationManager.authenticate(token);
        // 将返回的Authentication存到上下文中
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return "登录成功";
    }
}
@Autowired
private PasswordEncoder passwordEncoder;

@PostMapping("/register")
public String register(@RequestBody UserParam param) {
    UserEntity user = new UserEntity();
    // 调用加密器将前端传递过来的密码进行加密
    user.setUsername(param.getUsername()).setPassword(passwordEncoder.encode(param.getPassword()));
    // 将用户实体对象添加到数据库
    userService.save(user);
    return "注册成功";
}

认证管理器,调用,认证方法

d7b0908aa5fc9abb6969ebc49f0ad4c8.png
image.png
try
{
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
    AuthenticationContextHolder.setContext(authenticationToken);
    // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
    authentication = authenticationManager.authenticate(authenticationToken);
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
}
@Resource
private AuthenticationManager authenticationManager;

调用这个认证方法

authenticate
SysUser user = userService.selectUserByUserName(username);

通过用户名查询用户

7bcde2ae9d67aeb0003dd1066b968988.png
image.png
/**
 * 强散列哈希加密实现
 */
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
{
    return new BCryptPasswordEncoder();
}

/**
 * 身份认证接口
 */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
2532662fe9a0ce25d67debed8ac2f139.png
image.png

loadUserByUsername

SysUser user = userService.selectUserByUserName(username);
@Override
public SysUser selectUserByUserName(String userName)
{
    return userMapper.selectUserByUserName(userName);
}
public SysUser selectUserByUserName(String userName);
9e8ae9f14050fe90442063f8065ed30a.png
image.png
public class LoginUser implements UserDetails
{
}
{
    this.userId = userId;
    this.deptId = deptId;
    this.user = user;
    this.permissions = permissions;
}
public UserDetails createLoginUser(SysUser user)
{
    return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
    this.userId = userId;
    this.deptId = deptId;
    this.user = user;
    this.permissions = permissions;
}

@JSONField(serialize = false)
@Override
public String getPassword()
{
    return user.getPassword();
}
197e58e3710fda4e46bf34dd6e3d8073.png
image.png
d0dd50f2cea32222b25366ff95c2fa3b.png
image.png
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
/**
 * 设置用户代理信息
 *
 * @param loginUser 登录信息
 */
public void setUserAgent(LoginUser loginUser)
{
    UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
    String ip = IpUtils.getIpAddr();
    loginUser.setIpaddr(ip);
    loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
    loginUser.setBrowser(userAgent.getBrowser().getName());
    loginUser.setOs(userAgent.getOperatingSystem().getName());
}
String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
1e1103dfd657590c2d81e9ffcbced063.png
image.png
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
private String createToken(Map<String, Object> claims)
{
    String token = Jwts.builder()
            .setClaims(claims)
            .signWith(SignatureAlgorithm.HS512, secret).compact();
    return token;
}
token:
    # 令牌自定义标识
    header: Authorization
    # 令牌密钥
    secret: xxx
    # 令牌有效期(默认30分钟)
    expireTime: 30
return createToken(claims);

doFilterInternal

4642110aac0a0443112f88b863bfd146.png
image.png

https://zhuanlan.zhihu.com/p/342755411?utm medium=social&utm oi=1343915562263547904

01754e08a1d93ae37167b568c4836c7a.png
image.png
98582f83f9b1ba82ef8a3265ca30463c.png
image.png
5f103d91f25feb15c793e43c30b8cbb4.png
image.png
af42b00557da42066345bdb313f44a59.png
image.png
/**
 * 匿名访问不鉴权注解
 *
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}

PermitAllUrlProperties

647822e9eb259520882d91271207533a.png
image.png
aeb7c746027b65b438d1c40f6e61247b.png
image.png

https://cloud.tencentcom/document/product/400/35244

f05cf811a8de05ebfa9e330613f55470.png
image.png
d2c2c14e54d80ee4c2e080e20d653313.png
image.png
2fc876df68324a16f1b0d73286ad010a.png
image.png
0c8a98dda6e7c1251baeb34e699c593f.png
image.png
sudo /etc/init.d/bt default
a93181e0f31aa0e36df6c51685739f7c.png
image.png
cb580469075a4f4b545466545cca1d88.png
image.png
4c38896186467b8c9c54c7c87898d48b.png
image.png
db0a15e9fa0de606ddd4b8ba08442554.png
image.png

加群联系作者vx:xiaoda0423

仓库地址:https://github.com/webVueBlog/JavaGuideInterview

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值